<commit_before>#include "testing/testing.hpp"

#include "indexer/categories_holder.hpp"
#include "indexer/categories_index.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/new_feature_categories.hpp"

#include "editor/editor_config.hpp"

#include "coding/multilang_utf8_string.hpp"
#include "coding/reader.hpp"

#include "std/algorithm.hpp"
#include "std/bind.hpp"
#include "std/sstream.hpp"
#include "std/vector.hpp"
#include "std/transform_iterator.hpp"

#include "base/stl_helpers.hpp"

using namespace indexer;

char const g_testCategoriesTxt[] =
    "amenity-bench\n"
    "en:1bench|sit down|to sit\n"
    "de:0bank|auf die strafbank schicken\n"
    "zh-Hans:长凳\n"
    "zh-Hant:長板凳\n"
    "da:bænk\n"
    "\n"
    "place-village|place-hamlet\n"
    "en:village\n"
    "de:2dorf|4weiler";

struct Checker
{
  size_t & m_count;
  Checker(size_t & count) : m_count(count) {}
  void operator()(CategoriesHolder::Category const & cat)
  {
    switch (m_count)
    {
    case 0:
      {
        TEST_EQUAL(cat.m_synonyms.size(), 8, ());
        TEST_EQUAL(cat.m_synonyms[0].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
        TEST_EQUAL(cat.m_synonyms[0].m_name, "bench", ());
        TEST_EQUAL(cat.m_synonyms[0].m_prefixLengthToSuggest, 1, ());
        TEST_EQUAL(cat.m_synonyms[1].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
        TEST_EQUAL(cat.m_synonyms[1].m_name, "sit down", ());
        TEST_EQUAL(cat.m_synonyms[1].m_prefixLengthToSuggest, 10, ());
        TEST_EQUAL(cat.m_synonyms[2].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
        TEST_EQUAL(cat.m_synonyms[2].m_name, "to sit", ());
        TEST_EQUAL(cat.m_synonyms[3].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
        TEST_EQUAL(cat.m_synonyms[3].m_name, "bank", ());
        TEST_EQUAL(cat.m_synonyms[3].m_prefixLengthToSuggest, 0, ());
        TEST_EQUAL(cat.m_synonyms[4].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
        TEST_EQUAL(cat.m_synonyms[4].m_name, "auf die strafbank schicken", ());
        TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh_CN"), ());
        TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh_rCN"), ());
        TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh_HANS_CN"), ());
        TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh-Hans"), ());
        TEST_EQUAL(cat.m_synonyms[5].m_name, "长凳", ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh_TW"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh-MO"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh-rTW"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh_HANT_HK"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh_HK"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh-Hant"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_name, "長板凳", ());
        TEST_EQUAL(cat.m_synonyms[7].m_locale, CategoriesHolder::MapLocaleToInteger("da"), ());
        TEST_EQUAL(cat.m_synonyms[7].m_name, "bænk", ());
        ++m_count;
      }
      break;
    case 1:
    case 2:
      {
        TEST_EQUAL(cat.m_synonyms.size(), 3, ());
        TEST_EQUAL(cat.m_synonyms[0].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
        TEST_EQUAL(cat.m_synonyms[0].m_name, "village", ());
        TEST_EQUAL(cat.m_synonyms[1].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
        TEST_EQUAL(cat.m_synonyms[1].m_name, "dorf", ());
        TEST_EQUAL(cat.m_synonyms[1].m_prefixLengthToSuggest, 2, ());
        TEST_EQUAL(cat.m_synonyms[2].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
        TEST_EQUAL(cat.m_synonyms[2].m_name, "weiler", ());
        TEST_EQUAL(cat.m_synonyms[2].m_prefixLengthToSuggest, 4, ());
        ++m_count;
      }
      break;
    default:
      TEST(false, ("Too many categories"));
    }
  }
};

UNIT_TEST(LoadCategories)
{
  classificator::Load();

  CategoriesHolder h(make_unique<MemReader>(g_testCategoriesTxt, sizeof(g_testCategoriesTxt) - 1));
  size_t count = 0;
  Checker f(count);
  h.ForEachCategory(f);
  TEST_EQUAL(count, 3, ());
}

UNIT_TEST(CategoriesIndex_Smoke)
{
  classificator::Load();

  CategoriesHolder holder(
      make_unique<MemReader>(g_testCategoriesTxt, sizeof(g_testCategoriesTxt) - 1));
  CategoriesIndex index(holder);

  uint32_t type1 = classif().GetTypeByPath({"amenity", "bench"});
  uint32_t type2 = classif().GetTypeByPath({"place", "village"});
  if (type1 > type2)
    swap(type1, type2);
  int8_t lang1 = CategoriesHolder::MapLocaleToInteger("en");
  int8_t lang2 = CategoriesHolder::MapLocaleToInteger("de");

  auto testTypes = [&](string const & query, vector<uint32_t> const & expected)
  {
    vector<uint32_t> result;
    index.GetAssociatedTypes(query, result);
    TEST_EQUAL(result, expected, (query));
  };

  index.AddCategoryByTypeAndLang(type1, lang1);
  testTypes("bench", {type1});
  testTypes("BENCH", {type1});
  testTypes("down", {type1});
  testTypes("benck", {});
  testTypes("strafbank", {});
  index.AddCategoryByTypeAndLang(type1, lang2);
  testTypes("strafbank", {type1});
  testTypes("ie strafbank sc", {type1});
  testTypes("rafb", {type1});
  index.AddCategoryByTypeAndLang(type2, lang1);
  testTypes("i", {type1, type2});

  CategoriesIndex fullIndex(holder);
  fullIndex.AddCategoryByTypeAllLangs(type1);
  fullIndex.AddCategoryByTypeAllLangs(type2);
  vector<CategoriesHolder::Category> cats;

  // The letter 'a' matches "strafbank" and "village".
  // One language is not enough.
  fullIndex.GetCategories("a", cats);

  TEST_EQUAL(cats.size(), 2, ());

  TEST_EQUAL(cats[0].m_synonyms.size(), 8, ());
  TEST_EQUAL(cats[0].m_synonyms[4].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
  TEST_EQUAL(cats[0].m_synonyms[4].m_name, "auf die strafbank schicken", ());

  TEST_EQUAL(cats[1].m_synonyms.size(), 3, ());
  TEST_EQUAL(cats[1].m_synonyms[0].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
  TEST_EQUAL(cats[1].m_synonyms[0].m_name, "village", ());
}

UNIT_TEST(CategoriesIndex_MultipleTokens)
{
  char const kCategories[] =
      "shop-bakery\n"
      "en:shop of buns\n"
      "\n"
      "shop-butcher\n"
      "en:shop of meat";

  classificator::Load();
  CategoriesHolder holder(make_unique<MemReader>(kCategories, sizeof(kCategories) - 1));
  CategoriesIndex index(holder);

  index.AddAllCategoriesInAllLangs();
  auto testTypes = [&](string const & query, vector<uint32_t> const & expected)
  {
    vector<uint32_t> result;
    index.GetAssociatedTypes(query, result);
    TEST_EQUAL(result, expected, (query));
  };

  uint32_t type1 = classif().GetTypeByPath({"shop", "bakery"});
  uint32_t type2 = classif().GetTypeByPath({"shop", "butcher"});
  if (type1 > type2)
    swap(type1, type2);

  testTypes("shop", {type1, type2});
  testTypes("shop buns", {type1});
  testTypes("shop meat", {type2});
}

UNIT_TEST(CategoriesIndex_Groups)
{
  char const kCategories[] =
      "@shop\n"
      "en:shop\n"
      "ru:магазин\n"
      "\n"
      "@meat\n"
      "en:meat\n"
      "\n"
      "shop-bakery|@shop\n"
      "en:buns\n"
      "\n"
      "shop-butcher|@shop|@meat\n"
      "en:butcher\n"
      "";

  classificator::Load();
  CategoriesHolder holder(make_unique<MemReader>(kCategories, sizeof(kCategories) - 1));
  CategoriesIndex index(holder);

  index.AddAllCategoriesInAllLangs();
  auto testTypes = [&](string const & query, vector<uint32_t> const & expected)
  {
    vector<uint32_t> result;
    index.GetAssociatedTypes(query, result);
    TEST_EQUAL(result, expected, (query));
  };

  uint32_t type1 = classif().GetTypeByPath({"shop", "bakery"});
  uint32_t type2 = classif().GetTypeByPath({"shop", "butcher"});
  if (type1 > type2)
    swap(type1, type2);

  testTypes("buns", {type1});
  testTypes("butcher", {type2});
  testTypes("meat", {type2});
  testTypes("shop", {type1, type2});
  testTypes("магазин", {type1, type2});
  testTypes("http", {});
}

#ifdef DEBUG
// A check that this data structure is not too heavy.
UNIT_TEST(CategoriesIndex_AllCategories)
{
  classificator::Load();

  CategoriesIndex index;

  index.AddAllCategoriesInAllLangs();
  // Consider deprecating this method if this bound rises as high as a million.
  TEST_LESS(index.GetNumTrieNodes(), 400000, ());
}
#endif

#ifdef DEBUG
// A check that this data structure is not too heavy.
UNIT_TEST(CategoriesIndex_AllCategoriesEnglishName)
{
  classificator::Load();

  CategoriesIndex index;

  index.AddAllCategoriesInLang(CategoriesHolder::MapLocaleToInteger("en"));
  TEST_LESS(index.GetNumTrieNodes(), 6000, ());
}
#endif

UNIT_TEST(CategoriesIndex_UniqueNames)
{
  classificator::Load();
  auto const & cl = classif();

  editor::EditorConfig config;
  osm::NewFeatureCategories categories(config);

  bool noDuplicates = true;
  for (auto const & locale : CategoriesHolder::kLocaleMapping)
  {
    string const lang(locale.m_name);
    categories.AddLanguage(lang);
    auto const & names = categories.GetAllCategoryNames(lang);

    auto firstFn = bind(&pair<string, uint32_t>::first, _1);
    set<string> uniqueNames(make_transform_iterator(names.begin(), firstFn),
                            make_transform_iterator(names.end(), firstFn));

    if (uniqueNames.size() != names.size())
    {
      LOG(LWARNING, ("Invalid category translations", lang));

      for (size_t i = 1; i < names.size(); ++i)
      {
        if (names[i - 1].first == names[i].first)
        {
          noDuplicates = false;
          LOG(LWARNING, (names[i].first,
                         cl.GetReadableObjectName(names[i].second),
                         cl.GetReadableObjectName(names[i - 1].second)));
        }
      }

      LOG(LWARNING, ("+++++++++++++++++++++++++++++++++++++"));
    }
  };

  TEST(noDuplicates, ());
}
<commit_msg>Review fixes.<commit_after>#include "testing/testing.hpp"

#include "indexer/categories_holder.hpp"
#include "indexer/categories_index.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/new_feature_categories.hpp"

#include "editor/editor_config.hpp"

#include "coding/multilang_utf8_string.hpp"
#include "coding/reader.hpp"

#include "std/algorithm.hpp"
#include "std/bind.hpp"
#include "std/map.hpp"
#include "std/sstream.hpp"
#include "std/vector.hpp"
#include "std/transform_iterator.hpp"

#include "base/stl_helpers.hpp"

using namespace indexer;

char const g_testCategoriesTxt[] =
    "amenity-bench\n"
    "en:1bench|sit down|to sit\n"
    "de:0bank|auf die strafbank schicken\n"
    "zh-Hans:长凳\n"
    "zh-Hant:長板凳\n"
    "da:bænk\n"
    "\n"
    "place-village|place-hamlet\n"
    "en:village\n"
    "de:2dorf|4weiler";

struct Checker
{
  size_t & m_count;
  Checker(size_t & count) : m_count(count) {}
  void operator()(CategoriesHolder::Category const & cat)
  {
    switch (m_count)
    {
    case 0:
      {
        TEST_EQUAL(cat.m_synonyms.size(), 8, ());
        TEST_EQUAL(cat.m_synonyms[0].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
        TEST_EQUAL(cat.m_synonyms[0].m_name, "bench", ());
        TEST_EQUAL(cat.m_synonyms[0].m_prefixLengthToSuggest, 1, ());
        TEST_EQUAL(cat.m_synonyms[1].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
        TEST_EQUAL(cat.m_synonyms[1].m_name, "sit down", ());
        TEST_EQUAL(cat.m_synonyms[1].m_prefixLengthToSuggest, 10, ());
        TEST_EQUAL(cat.m_synonyms[2].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
        TEST_EQUAL(cat.m_synonyms[2].m_name, "to sit", ());
        TEST_EQUAL(cat.m_synonyms[3].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
        TEST_EQUAL(cat.m_synonyms[3].m_name, "bank", ());
        TEST_EQUAL(cat.m_synonyms[3].m_prefixLengthToSuggest, 0, ());
        TEST_EQUAL(cat.m_synonyms[4].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
        TEST_EQUAL(cat.m_synonyms[4].m_name, "auf die strafbank schicken", ());
        TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh_CN"), ());
        TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh_rCN"), ());
        TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh_HANS_CN"), ());
        TEST_EQUAL(cat.m_synonyms[5].m_locale, CategoriesHolder::MapLocaleToInteger("zh-Hans"), ());
        TEST_EQUAL(cat.m_synonyms[5].m_name, "长凳", ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh_TW"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh-MO"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh-rTW"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh_HANT_HK"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh_HK"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_locale, CategoriesHolder::MapLocaleToInteger("zh-Hant"), ());
        TEST_EQUAL(cat.m_synonyms[6].m_name, "長板凳", ());
        TEST_EQUAL(cat.m_synonyms[7].m_locale, CategoriesHolder::MapLocaleToInteger("da"), ());
        TEST_EQUAL(cat.m_synonyms[7].m_name, "bænk", ());
        ++m_count;
      }
      break;
    case 1:
    case 2:
      {
        TEST_EQUAL(cat.m_synonyms.size(), 3, ());
        TEST_EQUAL(cat.m_synonyms[0].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
        TEST_EQUAL(cat.m_synonyms[0].m_name, "village", ());
        TEST_EQUAL(cat.m_synonyms[1].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
        TEST_EQUAL(cat.m_synonyms[1].m_name, "dorf", ());
        TEST_EQUAL(cat.m_synonyms[1].m_prefixLengthToSuggest, 2, ());
        TEST_EQUAL(cat.m_synonyms[2].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
        TEST_EQUAL(cat.m_synonyms[2].m_name, "weiler", ());
        TEST_EQUAL(cat.m_synonyms[2].m_prefixLengthToSuggest, 4, ());
        ++m_count;
      }
      break;
    default:
      TEST(false, ("Too many categories"));
    }
  }
};

UNIT_TEST(LoadCategories)
{
  classificator::Load();

  CategoriesHolder h(make_unique<MemReader>(g_testCategoriesTxt, sizeof(g_testCategoriesTxt) - 1));
  size_t count = 0;
  Checker f(count);
  h.ForEachCategory(f);
  TEST_EQUAL(count, 3, ());
}

UNIT_TEST(CategoriesIndex_Smoke)
{
  classificator::Load();

  CategoriesHolder holder(
      make_unique<MemReader>(g_testCategoriesTxt, sizeof(g_testCategoriesTxt) - 1));
  CategoriesIndex index(holder);

  uint32_t type1 = classif().GetTypeByPath({"amenity", "bench"});
  uint32_t type2 = classif().GetTypeByPath({"place", "village"});
  if (type1 > type2)
    swap(type1, type2);
  int8_t lang1 = CategoriesHolder::MapLocaleToInteger("en");
  int8_t lang2 = CategoriesHolder::MapLocaleToInteger("de");

  auto testTypes = [&](string const & query, vector<uint32_t> const & expected)
  {
    vector<uint32_t> result;
    index.GetAssociatedTypes(query, result);
    TEST_EQUAL(result, expected, (query));
  };

  index.AddCategoryByTypeAndLang(type1, lang1);
  testTypes("bench", {type1});
  testTypes("BENCH", {type1});
  testTypes("down", {type1});
  testTypes("benck", {});
  testTypes("strafbank", {});
  index.AddCategoryByTypeAndLang(type1, lang2);
  testTypes("strafbank", {type1});
  testTypes("ie strafbank sc", {type1});
  testTypes("rafb", {type1});
  index.AddCategoryByTypeAndLang(type2, lang1);
  testTypes("i", {type1, type2});

  CategoriesIndex fullIndex(holder);
  fullIndex.AddCategoryByTypeAllLangs(type1);
  fullIndex.AddCategoryByTypeAllLangs(type2);
  vector<CategoriesHolder::Category> cats;

  // The letter 'a' matches "strafbank" and "village".
  // One language is not enough.
  fullIndex.GetCategories("a", cats);

  TEST_EQUAL(cats.size(), 2, ());

  TEST_EQUAL(cats[0].m_synonyms.size(), 8, ());
  TEST_EQUAL(cats[0].m_synonyms[4].m_locale, CategoriesHolder::MapLocaleToInteger("de"), ());
  TEST_EQUAL(cats[0].m_synonyms[4].m_name, "auf die strafbank schicken", ());

  TEST_EQUAL(cats[1].m_synonyms.size(), 3, ());
  TEST_EQUAL(cats[1].m_synonyms[0].m_locale, CategoriesHolder::MapLocaleToInteger("en"), ());
  TEST_EQUAL(cats[1].m_synonyms[0].m_name, "village", ());
}

UNIT_TEST(CategoriesIndex_MultipleTokens)
{
  char const kCategories[] =
      "shop-bakery\n"
      "en:shop of buns\n"
      "\n"
      "shop-butcher\n"
      "en:shop of meat";

  classificator::Load();
  CategoriesHolder holder(make_unique<MemReader>(kCategories, sizeof(kCategories) - 1));
  CategoriesIndex index(holder);

  index.AddAllCategoriesInAllLangs();
  auto testTypes = [&](string const & query, vector<uint32_t> const & expected)
  {
    vector<uint32_t> result;
    index.GetAssociatedTypes(query, result);
    TEST_EQUAL(result, expected, (query));
  };

  uint32_t type1 = classif().GetTypeByPath({"shop", "bakery"});
  uint32_t type2 = classif().GetTypeByPath({"shop", "butcher"});
  if (type1 > type2)
    swap(type1, type2);

  testTypes("shop", {type1, type2});
  testTypes("shop buns", {type1});
  testTypes("shop meat", {type2});
}

UNIT_TEST(CategoriesIndex_Groups)
{
  char const kCategories[] =
      "@shop\n"
      "en:shop\n"
      "ru:магазин\n"
      "\n"
      "@meat\n"
      "en:meat\n"
      "\n"
      "shop-bakery|@shop\n"
      "en:buns\n"
      "\n"
      "shop-butcher|@shop|@meat\n"
      "en:butcher\n"
      "";

  classificator::Load();
  CategoriesHolder holder(make_unique<MemReader>(kCategories, sizeof(kCategories) - 1));
  CategoriesIndex index(holder);

  index.AddAllCategoriesInAllLangs();
  auto testTypes = [&](string const & query, vector<uint32_t> const & expected)
  {
    vector<uint32_t> result;
    index.GetAssociatedTypes(query, result);
    TEST_EQUAL(result, expected, (query));
  };

  uint32_t type1 = classif().GetTypeByPath({"shop", "bakery"});
  uint32_t type2 = classif().GetTypeByPath({"shop", "butcher"});
  if (type1 > type2)
    swap(type1, type2);

  testTypes("buns", {type1});
  testTypes("butcher", {type2});
  testTypes("meat", {type2});
  testTypes("shop", {type1, type2});
  testTypes("магазин", {type1, type2});
  testTypes("http", {});
}

#ifdef DEBUG
// A check that this data structure is not too heavy.
UNIT_TEST(CategoriesIndex_AllCategories)
{
  classificator::Load();

  CategoriesIndex index;

  index.AddAllCategoriesInAllLangs();
  // Consider deprecating this method if this bound rises as high as a million.
  TEST_LESS(index.GetNumTrieNodes(), 400000, ());
}
#endif

#ifdef DEBUG
// A check that this data structure is not too heavy.
UNIT_TEST(CategoriesIndex_AllCategoriesEnglishName)
{
  classificator::Load();

  CategoriesIndex index;

  index.AddAllCategoriesInLang(CategoriesHolder::MapLocaleToInteger("en"));
  TEST_LESS(index.GetNumTrieNodes(), 6000, ());
}
#endif

UNIT_TEST(CategoriesIndex_UniqueNames)
{
  classificator::Load();
  auto const & cl = classif();

  editor::EditorConfig config;
  osm::NewFeatureCategories categories(config);

  bool noDuplicates = true;
  for (auto const & locale : CategoriesHolder::kLocaleMapping)
  {
    string const lang(locale.m_name);
    categories.AddLanguage(lang);
    auto const & names = categories.GetAllCategoryNames(lang);

    auto firstFn = bind(&pair<string, uint32_t>::first, _1);
    set<string> uniqueNames(make_transform_iterator(names.begin(), firstFn),
                            make_transform_iterator(names.end(), firstFn));
    if (uniqueNames.size() == names.size())
      continue;

    LOG(LWARNING, ("Invalid category translations", lang));

    map<string, vector<uint32_t>> typesByName;
    for (auto const & entry : names)
      typesByName[entry.first].push_back(entry.second);

    for (auto const & entry : typesByName)
    {
      if (entry.second.size() <= 1)
        continue;
      noDuplicates = false;
      ostringstream str;
      str << entry.first << ":";
      for (auto const & type : entry.second)
        str << " " << cl.GetReadableObjectName(type);
      LOG(LWARNING, (str.str()));
    }

    LOG(LWARNING,
        ("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"));
  };

  TEST(noDuplicates, ());
}
<|endoftext|>


<commit_before>// -*- Mode:C++ -*-

/**************************************************************************************************/
/*                                                                                */
/* Copyright (C) 2016 University of Hull                                                          */
/*                                                                                */
/**************************************************************************************************/
/*                                                                                */
/*  module     :  hugh/support/test/refcounted.cpp                                                */
/*  project    :                                                                                */
/*  description:                                                                                */
/*                                                                                */
/**************************************************************************************************/

// includes, system

#include <array>                   // std::array<>
#include <boost/intrusive_ptr.hpp> // boost::intrusive_ptr<>
#include <memory>                  // std::unique_ptr<>
#include <mutex>                   // std::mutex
#include <thread>                  // std::thread

// includes, project

#include <hugh/support/chrono.hpp>
#include <hugh/support/refcounted.hpp>

// internal unnamed namespace

namespace {

  // types, internal (class, enum, struct, union, typedef)

  class refcounted_test : public hugh::support::refcounted<refcounted_test> { /* ... */ };

  class refcount_user {

  public:

    explicit refcount_user(refcounted_test* a)
      : rt_(a)
    {}

    ~refcount_user()
    {}

  private:

    boost::intrusive_ptr<refcounted_test> rt_;

  };

  // variables, internal

  // functions, internal

} // namespace {

// functions, exported

#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(test_hugh_support_refcounted_ctor)
{
  boost::intrusive_ptr<refcounted_test> a(new refcounted_test);

  BOOST_CHECK(1 == a->use_count());
  {
    refcount_user b(a.get());

    BOOST_CHECK(2 == a->use_count());
  }
  BOOST_CHECK(1 == a->use_count());
}

BOOST_AUTO_TEST_CASE(test_hugh_support_refcounted_replace)
{
  boost::intrusive_ptr<refcounted_test> a(new refcounted_test);

  BOOST_CHECK(1 == a->use_count());
  {
    boost::intrusive_ptr<refcounted_test> b(a);

    BOOST_CHECK(a == b.get());
    BOOST_CHECK(2 == b->use_count());
    BOOST_CHECK(2 == a->use_count());

    b = new refcounted_test;

    BOOST_CHECK(a != b.get());
    BOOST_CHECK(1 == b->use_count());
    BOOST_CHECK(1 == a->use_count());
  }
  BOOST_CHECK(1 == a->use_count());
}

BOOST_AUTO_TEST_CASE(test_hugh_support_refcounted_async)
{
  std::string const                     l(20, '-');
  boost::intrusive_ptr<refcounted_test> a(new refcounted_test);

  BOOST_CHECK       (1 == a->use_count());
  BOOST_TEST_MESSAGE(std::this_thread::get_id() << ':' << a->use_count() << '\n' << l);

  {
    std::array<std::unique_ptr<std::thread>, 10> tp = { { } };
    std::chrono::microseconds const              d(tp.size());
    std::mutex                                   m;

    for (auto& t : tp) {
      t.reset(new std::thread([&]{
            refcount_user const b(a.get());

            {
              std::lock_guard<std::mutex> lk(m);

              BOOST_CHECK       (1           <  a->use_count());
              BOOST_CHECK       (tp.size()+1 >= a->use_count());
              BOOST_TEST_MESSAGE(std::this_thread::get_id() << ':' << a->use_count());
            }

            std::this_thread::sleep_for(d);
          }));

      t->detach();
    }

    std::this_thread::sleep_for((tp.size() * 3) * d);
  }

  BOOST_CHECK       (1 == a->use_count());
  BOOST_TEST_MESSAGE(l << '\n' << std::this_thread::get_id() << ':' << a->use_count());
}
<commit_msg>update: avoid timing-based test cases<commit_after>// -*- Mode:C++ -*-

/**************************************************************************************************/
/*                                                                                */
/* Copyright (C) 2016 University of Hull                                                          */
/*                                                                                */
/**************************************************************************************************/
/*                                                                                */
/*  module     :  hugh/support/test/refcounted.cpp                                                */
/*  project    :                                                                                */
/*  description:                                                                                */
/*                                                                                */
/**************************************************************************************************/

// includes, system

#include <array>                   // std::array<>
#include <boost/intrusive_ptr.hpp> // boost::intrusive_ptr<>
#include <condition_variable>      // std::condition_variable
#include <iomanip>                 // std::setfill, std::setw
#include <memory>                  // std::unique_ptr<>
#include <mutex>                   // std::mutex
#include <thread>                  // std::thread

// includes, project

#include <hugh/support/chrono.hpp>
#include <hugh/support/refcounted.hpp>

// internal unnamed namespace

namespace {

  // types, internal (class, enum, struct, union, typedef)

  class refcounted_test : public hugh::support::refcounted<refcounted_test> { /* ... */ };

  class refcount_user {

  public:

    explicit refcount_user(refcounted_test* a)
      : rt_(a)
    {}

    ~refcount_user()
    {}

  private:

    boost::intrusive_ptr<refcounted_test> rt_;

  };

  // variables, internal

  // functions, internal

} // namespace {

// functions, exported

#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(test_hugh_support_refcounted_ctor)
{
  boost::intrusive_ptr<refcounted_test> a(new refcounted_test);

  BOOST_CHECK(1 == a->use_count());
  {
    refcount_user b(a.get());

    BOOST_CHECK(2 == a->use_count());
  }
  BOOST_CHECK(1 == a->use_count());
}

BOOST_AUTO_TEST_CASE(test_hugh_support_refcounted_replace)
{
  boost::intrusive_ptr<refcounted_test> a(new refcounted_test);

  BOOST_CHECK(1 == a->use_count());
  {
    boost::intrusive_ptr<refcounted_test> b(a);

    BOOST_CHECK(a == b.get());
    BOOST_CHECK(2 == b->use_count());
    BOOST_CHECK(2 == a->use_count());

    b = new refcounted_test;

    BOOST_CHECK(a != b.get());
    BOOST_CHECK(1 == b->use_count());
    BOOST_CHECK(1 == a->use_count());
  }
  BOOST_CHECK(1 == a->use_count());
}

BOOST_AUTO_TEST_CASE(test_hugh_support_refcounted_async)
{
  std::string const                     l(20, '-');
  boost::intrusive_ptr<refcounted_test> a(new refcounted_test);

  BOOST_CHECK       (1 == a->use_count());
  BOOST_TEST_MESSAGE(std::right << std::setfill(' ') << std::setw(6)
                     <<std::this_thread::get_id() << ':' << a->use_count() << '\n' << l);

  {
    std::array<std::unique_ptr<std::thread>, 100> tp = { { } };
    unsigned                                     f(0);
    std::condition_variable                      cv;
    std::mutex                                   m;

    for (auto& t : tp) {
      t.reset(new std::thread([&]{
            refcount_user const b(a.get());

            {
              std::lock_guard<std::mutex> lk(m);

              ++f;

              BOOST_CHECK       (1           <  a->use_count());
              BOOST_CHECK       (tp.size()+1 >= a->use_count());
              BOOST_TEST_MESSAGE(std::right << std::setfill(' ') << std::setw(6)
                                 << std::this_thread::get_id() << ':' << a->use_count()
                                 << ':' << f);
            }

            cv.notify_one();
          }));

      t->detach();
    }

    {
      std::unique_lock<std::mutex> lk(m);

      cv.wait(lk, [&]{ return tp.size() <= f; });
    }
  }

  BOOST_CHECK       (1 == a->use_count());
  BOOST_TEST_MESSAGE(l << '\n'
                     << std::right << std::setfill(' ') << std::setw(6)
                     << std::this_thread::get_id() << ':' << a->use_count());
}
<|endoftext|>


<commit_before>/*

*/

#include "lineFollowing.h"

using namespace std;
using namespace cv;

ControlMovements lineFollowingControl() {

  line_main();

  return ControlMovements();
}

void line_main() {
//  printf("Hello, this is Caleb\n");

  VideoCapture cap("../../tests/videos/top_down_4.m4v");
  if (!cap.isOpened())  // check if we succeeded
    return;

  namedWindow("edges", CV_WINDOW_NORMAL);
  Mat edges;
  for (; ;) {
    Mat mask;
    Mat frame, gray;
    cap >> frame; // get a new frame from camera
    cvtColor(frame, gray, CV_BGR2HSV);

    Scalar low, high;
    low = Scalar(30, 0, 240);
    high = Scalar(80, 70, 255);

    inRange(gray, low, high, mask);

    vector <Vec4i> lines;
    HoughLinesP(mask, lines, 1, CV_PI / 180, 100, 100, 10);

    for (size_t i = 0; i < lines.size(); i++) {
      cout << "adding a line\n";
      Vec4i l = lines[i];
      line(frame, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, CV_AA);
    }

    imshow("edges", mask);
    if (waitKey(30) >= 0) break;
  }
  // the camera will be deinitialized automatically in VideoCapture destructor
  return;
}
<commit_msg>testing lines<commit_after>/*

*/

#include "lineFollowing.h"

using namespace std;
using namespace cv;

ControlMovements lineFollowingControl() {

  line_main();

  return ControlMovements();
}

void line_main() {
//  printf("Hello, this is Caleb\n");

  VideoCapture cap("../../tests/videos/top_down_4.m4v");
  if (!cap.isOpened())  // check if we succeeded
    return;

  namedWindow("edges", CV_WINDOW_NORMAL);
  Mat edges;
  for (; ;) {
    Mat mask;
    Mat frame, gray;
    cap >> frame; // get a new frame from camera
    cvtColor(frame, gray, CV_BGR2HSV);

    Scalar low, high;
    low = Scalar(30, 0, 240);
    high = Scalar(80, 70, 255);

    inRange(gray, low, high, mask);

    vector <Vec4i> lines;
    HoughLinesP(mask, lines, 1, CV_PI / 180, 100, 100, 10);

    for (size_t i = 0; i < lines.size(); i++) {
      Vec4i l = lines[i];
      line(frame, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, CV_AA);
    }

    imshow("edges", frame);
    if (waitKey(30) >= 0) break;
  }
  // the camera will be deinitialized automatically in VideoCapture destructor
  return;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#if ! defined INCLUDED_DP_COMMANDENVIRONMENTS_HXX
#define INCLUDED_DP_COMMANDENVIRONMENTS_HXX

#include "cppuhelper/compbase3.hxx"
#include "ucbhelper/content.hxx"
#include "com/sun/star/uno/Type.hxx"

namespace css = ::com::sun::star;

namespace dp_manager {

/**
   This command environment is to be used when an extension is temporarily
   stored in the "tmp" repository. It prevents all kind of user interaction.
 */
class BaseCommandEnv
    : public ::cppu::WeakImplHelper3< css::ucb::XCommandEnvironment,
                                      css::task::XInteractionHandler,
                                      css::ucb::XProgressHandler >
{
protected:
    css::uno::Reference< css::uno::XComponentContext > m_xContext;
    css::uno::Reference< css::task::XInteractionHandler> m_forwardHandler;

    void handle_(bool approve, bool abort,
                 css::uno::Reference< css::task::XInteractionRequest> const & xRequest );
public:
    virtual ~BaseCommandEnv();
    BaseCommandEnv();
    BaseCommandEnv(
        css::uno::Reference< css::task::XInteractionHandler> const & handler);

    // XCommandEnvironment
    virtual css::uno::Reference<css::task::XInteractionHandler > SAL_CALL
    getInteractionHandler() throw (css::uno::RuntimeException);
    virtual css::uno::Reference<css::ucb::XProgressHandler >
    SAL_CALL getProgressHandler() throw (css::uno::RuntimeException);

    // XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

    // XProgressHandler
    virtual void SAL_CALL push( css::uno::Any const & Status )
        throw (css::uno::RuntimeException);
    virtual void SAL_CALL update( css::uno::Any const & Status )
        throw (css::uno::RuntimeException);
    virtual void SAL_CALL pop() throw (css::uno::RuntimeException);
};

class TmpRepositoryCommandEnv : public BaseCommandEnv
{
public:
    TmpRepositoryCommandEnv();
    TmpRepositoryCommandEnv(css::uno::Reference< css::task::XInteractionHandler> const & handler);

// XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

};

/** this class is for use in XPackageManager::synchronize.

    It handles particular license cases.
 */
class LicenseCommandEnv : public BaseCommandEnv
{
private:
    ::rtl::OUString m_repository;
    bool m_bSuppressLicense;
public:
    LicenseCommandEnv(){};
    LicenseCommandEnv(
        css::uno::Reference< css::task::XInteractionHandler> const & handler,
        bool bSuppressLicense,
        ::rtl::OUString const & repository);

// XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

};

/** this class is for use in XPackageManager::checkPrerequisites

    It always prohibits a license interaction
 */
class NoLicenseCommandEnv : public BaseCommandEnv
{

public:
    NoLicenseCommandEnv(){};
    NoLicenseCommandEnv(css::uno::Reference< css::task::XInteractionHandler> const & handler);

// XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

};

/* For use in XExtensionManager::addExtension in the call to
   XPackage::checkPrerequisites
   It prevents all user interactions. The license is always accepted.
   It remembers if there was a platform or a dependency exception in
   the member m_bException. if there was any other exception then m_bUnknownException
   is set.

 */
class SilentCheckPrerequisitesCommandEnv : public BaseCommandEnv
{
public:
    SilentCheckPrerequisitesCommandEnv();
    // XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

    // Set to true if a PlatformException or a DependencyException were handled.
    css::uno::Any m_Exception;
    // Set to true if an unknown exception was handled.
    css::uno::Any m_UnknownException;
};

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>cppcheck: uninitialized member variable<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#if ! defined INCLUDED_DP_COMMANDENVIRONMENTS_HXX
#define INCLUDED_DP_COMMANDENVIRONMENTS_HXX

#include "cppuhelper/compbase3.hxx"
#include "ucbhelper/content.hxx"
#include "com/sun/star/uno/Type.hxx"

namespace css = ::com::sun::star;

namespace dp_manager {

/**
   This command environment is to be used when an extension is temporarily
   stored in the "tmp" repository. It prevents all kind of user interaction.
 */
class BaseCommandEnv
    : public ::cppu::WeakImplHelper3< css::ucb::XCommandEnvironment,
                                      css::task::XInteractionHandler,
                                      css::ucb::XProgressHandler >
{
protected:
    css::uno::Reference< css::uno::XComponentContext > m_xContext;
    css::uno::Reference< css::task::XInteractionHandler> m_forwardHandler;

    void handle_(bool approve, bool abort,
                 css::uno::Reference< css::task::XInteractionRequest> const & xRequest );
public:
    virtual ~BaseCommandEnv();
    BaseCommandEnv();
    BaseCommandEnv(
        css::uno::Reference< css::task::XInteractionHandler> const & handler);

    // XCommandEnvironment
    virtual css::uno::Reference<css::task::XInteractionHandler > SAL_CALL
    getInteractionHandler() throw (css::uno::RuntimeException);
    virtual css::uno::Reference<css::ucb::XProgressHandler >
    SAL_CALL getProgressHandler() throw (css::uno::RuntimeException);

    // XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

    // XProgressHandler
    virtual void SAL_CALL push( css::uno::Any const & Status )
        throw (css::uno::RuntimeException);
    virtual void SAL_CALL update( css::uno::Any const & Status )
        throw (css::uno::RuntimeException);
    virtual void SAL_CALL pop() throw (css::uno::RuntimeException);
};

class TmpRepositoryCommandEnv : public BaseCommandEnv
{
public:
    TmpRepositoryCommandEnv();
    TmpRepositoryCommandEnv(css::uno::Reference< css::task::XInteractionHandler> const & handler);

// XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

};

/** this class is for use in XPackageManager::synchronize.

    It handles particular license cases.
 */
class LicenseCommandEnv : public BaseCommandEnv
{
private:
    ::rtl::OUString m_repository;
    bool m_bSuppressLicense;
public:
    LicenseCommandEnv() : m_bSuppressLicense(false) {};
    LicenseCommandEnv(
        css::uno::Reference< css::task::XInteractionHandler> const & handler,
        bool bSuppressLicense,
        ::rtl::OUString const & repository);

// XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

};

/** this class is for use in XPackageManager::checkPrerequisites

    It always prohibits a license interaction
 */
class NoLicenseCommandEnv : public BaseCommandEnv
{

public:
    NoLicenseCommandEnv(){};
    NoLicenseCommandEnv(css::uno::Reference< css::task::XInteractionHandler> const & handler);

// XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

};

/* For use in XExtensionManager::addExtension in the call to
   XPackage::checkPrerequisites
   It prevents all user interactions. The license is always accepted.
   It remembers if there was a platform or a dependency exception in
   the member m_bException. if there was any other exception then m_bUnknownException
   is set.

 */
class SilentCheckPrerequisitesCommandEnv : public BaseCommandEnv
{
public:
    SilentCheckPrerequisitesCommandEnv();
    // XInteractionHandler
    virtual void SAL_CALL handle(
        css::uno::Reference<css::task::XInteractionRequest > const & xRequest )
        throw (css::uno::RuntimeException);

    // Set to true if a PlatformException or a DependencyException were handled.
    css::uno::Any m_Exception;
    // Set to true if an unknown exception was handled.
    css::uno::Any m_UnknownException;
};

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// Copyright (c) 2006-2009 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.

// This test is POSIX only.

#include <unistd.h>
#include <fcntl.h>

#include "base/basictypes.h"
#include "base/eintr_wrapper.h"
#include "ipc/file_descriptor_set_posix.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

// Get a safe file descriptor for test purposes.
int GetSafeFd() {
  return open("/dev/null", O_RDONLY);
}

// Returns true if fd was already closed.  Closes fd if not closed.
bool VerifyClosed(int fd) {
  const int duped = dup(fd);
  if (duped != -1) {
    HANDLE_EINTR(close(duped));
    HANDLE_EINTR(close(fd));
    return false;
  }
  return true;
}

// The FileDescriptorSet will try and close some of the descriptor numbers
// which we given it. This is the base descriptor value. It's great enough such
// that no real descriptor will accidently be closed.
static const int kFDBase = 50000;

TEST(FileDescriptorSet, BasicAdd) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_EQ(set->size(), 0u);
  ASSERT_TRUE(set->empty());
  ASSERT_TRUE(set->Add(kFDBase));
  ASSERT_EQ(set->size(), 1u);
  ASSERT_TRUE(!set->empty());

  // Empties the set and stops a warning about deleting a set with unconsumed
  // descriptors
  set->CommitAll();
}

TEST(FileDescriptorSet, BasicAddAndClose) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_EQ(set->size(), 0u);
  ASSERT_TRUE(set->empty());
  const int fd = GetSafeFd();
  ASSERT_TRUE(set->AddAndAutoClose(fd));
  ASSERT_EQ(set->size(), 1u);
  ASSERT_TRUE(!set->empty());

  set->CommitAll();

  ASSERT_TRUE(VerifyClosed(fd));
}
TEST(FileDescriptorSet, MaxSize) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  for (unsigned i = 0;
       i < FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE; ++i) {
    ASSERT_TRUE(set->Add(kFDBase + 1 + i));
  }

  ASSERT_TRUE(!set->Add(kFDBase));

  set->CommitAll();
}

TEST(FileDescriptorSet, SetDescriptors) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_TRUE(set->empty());
  set->SetDescriptors(NULL, 0);
  ASSERT_TRUE(set->empty());

  const int fd = GetSafeFd();
  static const int fds[] = {fd};
  set->SetDescriptors(fds, 1);
  ASSERT_TRUE(!set->empty());
  ASSERT_EQ(set->size(), 1u);

  set->CommitAll();

  ASSERT_TRUE(VerifyClosed(fd));
}

TEST(FileDescriptorSet, GetDescriptors) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  set->GetDescriptors(NULL);
  ASSERT_TRUE(set->Add(kFDBase));

  int fds[1];
  fds[0] = 0;
  set->GetDescriptors(fds);
  ASSERT_EQ(fds[0], kFDBase);
  set->CommitAll();
  ASSERT_TRUE(set->empty());
}

TEST(FileDescriptorSet, WalkInOrder) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_TRUE(set->Add(kFDBase));
  ASSERT_TRUE(set->Add(kFDBase + 1));
  ASSERT_TRUE(set->Add(kFDBase + 2));

  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
  ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);

  set->CommitAll();
}

TEST(FileDescriptorSet, WalkWrongOrder) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_TRUE(set->Add(kFDBase));
  ASSERT_TRUE(set->Add(kFDBase + 1));
  ASSERT_TRUE(set->Add(kFDBase + 2));

  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(2), -1);

  set->CommitAll();
}

TEST(FileDescriptorSet, WalkCycle) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_TRUE(set->Add(kFDBase));
  ASSERT_TRUE(set->Add(kFDBase + 1));
  ASSERT_TRUE(set->Add(kFDBase + 2));

  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
  ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);
  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
  ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);
  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
  ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);

  set->CommitAll();
}

TEST(FileDescriptorSet, DontClose) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  const int fd = GetSafeFd();
  ASSERT_TRUE(set->Add(fd));
  set->CommitAll();

  ASSERT_FALSE(VerifyClosed(fd));
}

TEST(FileDescriptorSet, DoClose) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  const int fd = GetSafeFd();
  ASSERT_TRUE(set->AddAndAutoClose(fd));
  set->CommitAll();

  ASSERT_TRUE(VerifyClosed(fd));
}

}  // namespace
<commit_msg>Handle return value from HANDLE_EINTR in file_descriptor_set_posix_unittest.cc.<commit_after>// Copyright (c) 2006-2009 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.

// This test is POSIX only.

#include <unistd.h>
#include <fcntl.h>

#include "base/basictypes.h"
#include "base/eintr_wrapper.h"
#include "ipc/file_descriptor_set_posix.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

// Get a safe file descriptor for test purposes.
int GetSafeFd() {
  return open("/dev/null", O_RDONLY);
}

// Returns true if fd was already closed.  Closes fd if not closed.
bool VerifyClosed(int fd) {
  const int duped = dup(fd);
  if (duped != -1) {
    EXPECT_NE(HANDLE_EINTR(close(duped)), -1);
    EXPECT_NE(HANDLE_EINTR(close(fd)), -1);
    return false;
  }
  return true;
}

// The FileDescriptorSet will try and close some of the descriptor numbers
// which we given it. This is the base descriptor value. It's great enough such
// that no real descriptor will accidently be closed.
static const int kFDBase = 50000;

TEST(FileDescriptorSet, BasicAdd) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_EQ(set->size(), 0u);
  ASSERT_TRUE(set->empty());
  ASSERT_TRUE(set->Add(kFDBase));
  ASSERT_EQ(set->size(), 1u);
  ASSERT_TRUE(!set->empty());

  // Empties the set and stops a warning about deleting a set with unconsumed
  // descriptors
  set->CommitAll();
}

TEST(FileDescriptorSet, BasicAddAndClose) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_EQ(set->size(), 0u);
  ASSERT_TRUE(set->empty());
  const int fd = GetSafeFd();
  ASSERT_TRUE(set->AddAndAutoClose(fd));
  ASSERT_EQ(set->size(), 1u);
  ASSERT_TRUE(!set->empty());

  set->CommitAll();

  ASSERT_TRUE(VerifyClosed(fd));
}
TEST(FileDescriptorSet, MaxSize) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  for (unsigned i = 0;
       i < FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE; ++i) {
    ASSERT_TRUE(set->Add(kFDBase + 1 + i));
  }

  ASSERT_TRUE(!set->Add(kFDBase));

  set->CommitAll();
}

TEST(FileDescriptorSet, SetDescriptors) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_TRUE(set->empty());
  set->SetDescriptors(NULL, 0);
  ASSERT_TRUE(set->empty());

  const int fd = GetSafeFd();
  static const int fds[] = {fd};
  set->SetDescriptors(fds, 1);
  ASSERT_TRUE(!set->empty());
  ASSERT_EQ(set->size(), 1u);

  set->CommitAll();

  ASSERT_TRUE(VerifyClosed(fd));
}

TEST(FileDescriptorSet, GetDescriptors) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  set->GetDescriptors(NULL);
  ASSERT_TRUE(set->Add(kFDBase));

  int fds[1];
  fds[0] = 0;
  set->GetDescriptors(fds);
  ASSERT_EQ(fds[0], kFDBase);
  set->CommitAll();
  ASSERT_TRUE(set->empty());
}

TEST(FileDescriptorSet, WalkInOrder) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_TRUE(set->Add(kFDBase));
  ASSERT_TRUE(set->Add(kFDBase + 1));
  ASSERT_TRUE(set->Add(kFDBase + 2));

  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
  ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);

  set->CommitAll();
}

TEST(FileDescriptorSet, WalkWrongOrder) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_TRUE(set->Add(kFDBase));
  ASSERT_TRUE(set->Add(kFDBase + 1));
  ASSERT_TRUE(set->Add(kFDBase + 2));

  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(2), -1);

  set->CommitAll();
}

TEST(FileDescriptorSet, WalkCycle) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  ASSERT_TRUE(set->Add(kFDBase));
  ASSERT_TRUE(set->Add(kFDBase + 1));
  ASSERT_TRUE(set->Add(kFDBase + 2));

  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
  ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);
  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
  ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);
  ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
  ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
  ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);

  set->CommitAll();
}

TEST(FileDescriptorSet, DontClose) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  const int fd = GetSafeFd();
  ASSERT_TRUE(set->Add(fd));
  set->CommitAll();

  ASSERT_FALSE(VerifyClosed(fd));
}

TEST(FileDescriptorSet, DoClose) {
  scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet;

  const int fd = GetSafeFd();
  ASSERT_TRUE(set->AddAndAutoClose(fd));
  set->CommitAll();

  ASSERT_TRUE(VerifyClosed(fd));
}

}  // namespace
<|endoftext|>


<commit_before>#include "raven_client.h"

#include <time.h>

#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <QHostAddress>
#include <QHostInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkInterface>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUuid>

namespace {

int g_next_request_id;

char kRequestIdProperty[] = "RequestIdProperty";

}

const char Raven::kClientName[] = "Raven-Qt";
const char Raven::kClientVersion[] = "0.2";

Raven* g_client;

Raven::Raven()
  : initialized_(false) {
    g_client = this;
}

Raven::~Raven() {
    waitForIdle();
    Q_ASSERT(pending_request_.isEmpty());
    g_client = NULL;
}

// static
Raven* Raven::instance() {
    if (!g_client)
        g_client = new Raven();

    return g_client;
}

bool Raven::initialize(const QString& DSN) {
    waitLoop_ = 0;
    // If an empty DSN is passed, you should treat it as valid option
    // which signifies disabling the client.
    if (DSN.isEmpty()) {
        qDebug() << "Raven client is disabled.";
        return true;
    }

    QUrl url(DSN);
    if (!url.isValid())
        return false;

    protocol_ = url.scheme();
    public_key_ = url.userName();
    secret_key_ = url.password();
    host_ = url.host();
    path_ = url.path();
    project_id_ = url.fileName();

    int i = path_.lastIndexOf('/');
    if (i >= 0)
        path_ = path_.left(i);

    int port = url.port(80);
    if (port != 80)
        host_.append(":").append(QString::number(port));

    qDebug() << "Raven client is ready.";

    initialized_ = true;
    return true;
}

void Raven::waitForIdle()
{
    if ( waitLoop_ )
    {
        qCritical() << "Recursive call Raven::waitForIdle";
        return;
    }

    if (pending_request_.size()) {
        QEventLoop loop;
        QTimer timer;
        timer.setSingleShot( true );
        QObject::connect( &timer, SIGNAL( timeout() ), &loop, SLOT( quit() ) );
        waitLoop_ = &loop;
        timer.start( 2000 );
        loop.exec( QEventLoop::ExcludeUserInputEvents );
        if ( timer.isActive() ) qDebug() << "Raven loop ended on timeout.";
        waitLoop_ = 0;
    }
}

void Raven::set_global_tags(const QString& key, const QString& value) {
    if (!key.isEmpty() && !value.isEmpty())
        global_tags_[key] = value;
}

void Raven::set_user_data(const QString& key, const QString& value) {
    if (!key.isEmpty() && !value.isEmpty())
        user_data_[key] = value;
}

// static
// According to http://sentry.readthedocs.org/en/latest/developer/client/
void Raven::captureMessage(
    Level level,
    const QString& from_here,
    const QString& message,
    QJsonObject extra,
    QJsonObject tags) {
    Raven* instance = Raven::instance();
    if (!instance->initialized_) {
        qDebug() << "Sentry has not been initialized succefully. Failed to send message.";
        return;
    }

    QJsonObject jdata;
    jdata["event_id"] = QUuid::createUuid().toString();
    jdata["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
    jdata["server_name"] = QHostInfo::localHostName();
    jdata["user"] = instance->GetUserInfo();
    jdata["level"] = GetLevelString(level);
    jdata["culprit"] = from_here;
    jdata["message"] = message;
    jdata["logger"] = kClientName;
    jdata["platform"] = "C++/Qt";

    // Add global tags
    const QJsonObject& gtags = instance->global_tags_;
    if (!gtags.isEmpty()) {
        for (auto it = gtags.begin(); it != gtags.end(); ++it)
            tags[it.key()] = *it;
    }

    if (!tags.isEmpty())
        jdata["tags"] = tags;
    if (!extra.isEmpty())
        jdata["extra"] = extra;

    //jdata["modules"] = QJsonObject();

    instance->Send(jdata);
}

void Raven::Send(const QJsonObject& jbody) {
    QString client_info = QString("%1/%2").
        arg(kClientName).arg(kClientVersion);

    QString auth_info = QString("Sentry sentry_version=5,sentry_client=%1,sentry_timestamp=%2,sentry_key=%3,sentry_secret=%4").
        arg(client_info, QString::number(time(NULL)), public_key_, secret_key_);

    // http://192.168.1.x:9000/api/4/store/
    QString url = QString("%1://%2%3/api/%4/store/").
        arg(protocol_).arg(host_).arg(path_).arg(project_id_);

    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    request.setHeader(QNetworkRequest::UserAgentHeader, client_info);
    request.setRawHeader("X-Sentry-Auth", auth_info.toUtf8());

    QByteArray body = QJsonDocument(jbody).toJson(QJsonDocument::Indented);

    QNetworkReply* reply = network_access_manager_.post(request, body);
    reply->setProperty(kRequestIdProperty, QVariant(++g_next_request_id));
    pending_request_[g_next_request_id] = body;
    ConnectReply(reply);
}

void Raven::ConnectReply(QNetworkReply* reply) {
    connect(reply, SIGNAL(finished()), this, SLOT(slotFinished()));
    connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(slotSslError(const QList<QSslError>&)));
}

void Raven::slotFinished() {
    QNetworkReply* reply = static_cast<QNetworkReply*>(sender());

    int id = GetRequestId(reply);
    if (pending_request_.find(id) == pending_request_.end()) {
        reply->deleteLater();
        if ( pending_request_.isEmpty() && waitLoop_ ) waitLoop_->exit();
        return;
    }

    // Deal with redirection
    QUrl possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
    if (!possibleRedirectUrl.isEmpty() && possibleRedirectUrl != reply->url()) {
        QNetworkRequest request = reply->request();
        QByteArray body = pending_request_[id];
        request.setUrl(possibleRedirectUrl);
        QNetworkReply* new_reply = network_access_manager_.post(request, body);
        new_reply->setProperty(kRequestIdProperty, QVariant(id));
        ConnectReply(new_reply);
    } else {
        QNetworkReply::NetworkError e = reply->error();
        QByteArray res = reply->readAll();
        if (e == QNetworkReply::NoError) {
            qDebug() << "Sentry log ID " << res;
        }
        else {
            qDebug() << "Failed to send log to sentry: [" << e << "]:" << res;
        }

        pending_request_.remove(id);
    }

    if (pending_request_.isEmpty() && waitLoop_ )
        waitLoop_->exit();

    reply->deleteLater();
}

void Raven::slotSslError(const QList<QSslError>& ) {
    QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
    reply->ignoreSslErrors();
}

int Raven::GetRequestId(QNetworkReply* reply) {
    QVariant var = reply->property(kRequestIdProperty);
    if (var.type() != QVariant::Int)
        return kInvalidRequestId;

    return var.toInt();
}

QJsonObject Raven::GetUserInfo() {
    QJsonObject user;
    if (!user_id_.isEmpty())
        user["id"] = user_id_;
    if (!user_name_.isEmpty())
        user["username"] = user_name_;
    if (!user_email_.isEmpty())
        user["email"] = user_email_;

    if (!user_data_.isEmpty()) {
        for (auto it = user_data_.begin(); it != user_data_.end(); ++it)
            user[it.key()] = *it;
    }

    user["ip_address"] = LocalAddress();
    return user;
}

QString Raven::LocalAddress() {
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    for (int nIter = 0; nIter < list.count(); nIter++) {
        if (!list[nIter].isLoopback()) {
            if (list[nIter].protocol() == QAbstractSocket::IPv4Protocol)
                return list[nIter].toString();
        }
    }

    return "0.0.0.0";
}

// static
QString Raven::locationInfo(const char* file, const char* func, int line) {
    return QString("%1 in %2 at %3").arg(file).arg(func).arg(QString::number(line));
}

// static
Raven::Level Raven::fromUnixLogLevel(int i) {
    Level level;
    switch (i) {
    case 7:  //Debug
        level = Raven::kDebug;
        break;
    case 6:  //Info
    case 5:  //Notice
        level = Raven::kInfo;
        break;
    case 4:  //Warning
        level = Raven::kWarning;
        break;
    case 3:  //Error
    case 2:  //Critical
    case 1:  //Alert
        level = Raven::kError;
        break;
    case 0:  //Emergency
        level = Raven::kFatal;
        break;
    default:
        level = Raven::kDebug;
        break;
    }

    return level;
}

// static
QString Raven::GetLevelString(Level level) {
    QString s;
    switch (level) {
    case kDebug:
        s = "debug";
        break;
    case kInfo:
        s = "info";
        break;
    case kWarning:
        s = "warning";
        break;
    case kError:
        s = "error";
        break;
    case kFatal:
        s = "fatal";
        break;
    default:
        qDebug() << "Wrong sentry log level, default to error.";
        s = "error";
        break;
    }

    return s;
}
<commit_msg>Debug updates - report on finish<commit_after>#include "raven_client.h"

#include <time.h>

#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <QHostAddress>
#include <QHostInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkInterface>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUuid>

namespace {

int g_next_request_id;

char kRequestIdProperty[] = "RequestIdProperty";

}

const char Raven::kClientName[] = "Raven-Qt";
const char Raven::kClientVersion[] = "0.2";

Raven* g_client;

Raven::Raven()
  : initialized_(false) {
    g_client = this;
}

Raven::~Raven() {
    waitForIdle();
    Q_ASSERT(pending_request_.isEmpty());
    g_client = NULL;
}

// static
Raven* Raven::instance() {
    if (!g_client)
        g_client = new Raven();

    return g_client;
}

bool Raven::initialize(const QString& DSN) {
    waitLoop_ = 0;
    // If an empty DSN is passed, you should treat it as valid option
    // which signifies disabling the client.
    if (DSN.isEmpty()) {
        qDebug() << "Raven client is disabled.";
        return true;
    }

    QUrl url(DSN);
    if (!url.isValid())
        return false;

    protocol_ = url.scheme();
    public_key_ = url.userName();
    secret_key_ = url.password();
    host_ = url.host();
    path_ = url.path();
    project_id_ = url.fileName();

    int i = path_.lastIndexOf('/');
    if (i >= 0)
        path_ = path_.left(i);

    int port = url.port(80);
    if (port != 80)
        host_.append(":").append(QString::number(port));

    qDebug() << "Raven client is ready.";

    initialized_ = true;
    return true;
}

void Raven::waitForIdle()
{
    if ( waitLoop_ )
    {
        qCritical() << "Recursive call Raven::waitForIdle";
        return;
    }

    if (pending_request_.size()) {
        QEventLoop loop;
        QTimer timer;
        timer.setSingleShot( true );
        QObject::connect( &timer, SIGNAL( timeout() ), &loop, SLOT( quit() ) );
        waitLoop_ = &loop;
        const int timeout = 2000;
        timer.start( timeout );
        loop.exec( QEventLoop::ExcludeUserInputEvents );
        if ( timer.isActive() ) qDebug() << "Raven client finished, took " << timeout - timer.remainingTime() << " ms";
        else qDebug() << "Raven loop ended on timeout.";
        waitLoop_ = 0;
    }
}

void Raven::set_global_tags(const QString& key, const QString& value) {
    if (!key.isEmpty() && !value.isEmpty())
        global_tags_[key] = value;
}

void Raven::set_user_data(const QString& key, const QString& value) {
    if (!key.isEmpty() && !value.isEmpty())
        user_data_[key] = value;
}

// static
// According to http://sentry.readthedocs.org/en/latest/developer/client/
void Raven::captureMessage(
    Level level,
    const QString& from_here,
    const QString& message,
    QJsonObject extra,
    QJsonObject tags) {
    Raven* instance = Raven::instance();
    if (!instance->initialized_) {
        qDebug() << "Sentry has not been initialized succefully. Failed to send message.";
        return;
    }

    QJsonObject jdata;
    jdata["event_id"] = QUuid::createUuid().toString();
    jdata["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
    jdata["server_name"] = QHostInfo::localHostName();
    jdata["user"] = instance->GetUserInfo();
    jdata["level"] = GetLevelString(level);
    jdata["culprit"] = from_here;
    jdata["message"] = message;
    jdata["logger"] = kClientName;
    jdata["platform"] = "C++/Qt";

    // Add global tags
    const QJsonObject& gtags = instance->global_tags_;
    if (!gtags.isEmpty()) {
        for (auto it = gtags.begin(); it != gtags.end(); ++it)
            tags[it.key()] = *it;
    }

    if (!tags.isEmpty())
        jdata["tags"] = tags;
    if (!extra.isEmpty())
        jdata["extra"] = extra;

    //jdata["modules"] = QJsonObject();

    instance->Send(jdata);
}

void Raven::Send(const QJsonObject& jbody) {
    QString client_info = QString("%1/%2").
        arg(kClientName).arg(kClientVersion);

    QString auth_info = QString("Sentry sentry_version=5,sentry_client=%1,sentry_timestamp=%2,sentry_key=%3,sentry_secret=%4").
        arg(client_info, QString::number(time(NULL)), public_key_, secret_key_);

    // http://192.168.1.x:9000/api/4/store/
    QString url = QString("%1://%2%3/api/%4/store/").
        arg(protocol_).arg(host_).arg(path_).arg(project_id_);

    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    request.setHeader(QNetworkRequest::UserAgentHeader, client_info);
    request.setRawHeader("X-Sentry-Auth", auth_info.toUtf8());

    QByteArray body = QJsonDocument(jbody).toJson(QJsonDocument::Indented);

    QNetworkReply* reply = network_access_manager_.post(request, body);
    reply->setProperty(kRequestIdProperty, QVariant(++g_next_request_id));
    pending_request_[g_next_request_id] = body;
    ConnectReply(reply);
}

void Raven::ConnectReply(QNetworkReply* reply) {
    connect(reply, SIGNAL(finished()), this, SLOT(slotFinished()));
    connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(slotSslError(const QList<QSslError>&)));
}

void Raven::slotFinished() {
    QNetworkReply* reply = static_cast<QNetworkReply*>(sender());

    int id = GetRequestId(reply);
    if (pending_request_.find(id) == pending_request_.end()) {
        reply->deleteLater();
        if ( pending_request_.isEmpty() && waitLoop_ ) waitLoop_->exit();
        return;
    }

    // Deal with redirection
    QUrl possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
    if (!possibleRedirectUrl.isEmpty() && possibleRedirectUrl != reply->url()) {
        QNetworkRequest request = reply->request();
        QByteArray body = pending_request_[id];
        request.setUrl(possibleRedirectUrl);
        QNetworkReply* new_reply = network_access_manager_.post(request, body);
        new_reply->setProperty(kRequestIdProperty, QVariant(id));
        ConnectReply(new_reply);
    } else {
        QNetworkReply::NetworkError e = reply->error();
        QByteArray res = reply->readAll();
        if (e == QNetworkReply::NoError) {
            qDebug() << "Sentry log ID " << res;
        }
        else {
            qDebug() << "Failed to send log to sentry: [" << e << "]:" << res;
        }

        pending_request_.remove(id);
    }

    if (pending_request_.isEmpty() && waitLoop_ )
        waitLoop_->exit();

    reply->deleteLater();
}

void Raven::slotSslError(const QList<QSslError>& ) {
    QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
    reply->ignoreSslErrors();
}

int Raven::GetRequestId(QNetworkReply* reply) {
    QVariant var = reply->property(kRequestIdProperty);
    if (var.type() != QVariant::Int)
        return kInvalidRequestId;

    return var.toInt();
}

QJsonObject Raven::GetUserInfo() {
    QJsonObject user;
    if (!user_id_.isEmpty())
        user["id"] = user_id_;
    if (!user_name_.isEmpty())
        user["username"] = user_name_;
    if (!user_email_.isEmpty())
        user["email"] = user_email_;

    if (!user_data_.isEmpty()) {
        for (auto it = user_data_.begin(); it != user_data_.end(); ++it)
            user[it.key()] = *it;
    }

    user["ip_address"] = LocalAddress();
    return user;
}

QString Raven::LocalAddress() {
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    for (int nIter = 0; nIter < list.count(); nIter++) {
        if (!list[nIter].isLoopback()) {
            if (list[nIter].protocol() == QAbstractSocket::IPv4Protocol)
                return list[nIter].toString();
        }
    }

    return "0.0.0.0";
}

// static
QString Raven::locationInfo(const char* file, const char* func, int line) {
    return QString("%1 in %2 at %3").arg(file).arg(func).arg(QString::number(line));
}

// static
Raven::Level Raven::fromUnixLogLevel(int i) {
    Level level;
    switch (i) {
    case 7:  //Debug
        level = Raven::kDebug;
        break;
    case 6:  //Info
    case 5:  //Notice
        level = Raven::kInfo;
        break;
    case 4:  //Warning
        level = Raven::kWarning;
        break;
    case 3:  //Error
    case 2:  //Critical
    case 1:  //Alert
        level = Raven::kError;
        break;
    case 0:  //Emergency
        level = Raven::kFatal;
        break;
    default:
        level = Raven::kDebug;
        break;
    }

    return level;
}

// static
QString Raven::GetLevelString(Level level) {
    QString s;
    switch (level) {
    case kDebug:
        s = "debug";
        break;
    case kInfo:
        s = "info";
        break;
    case kWarning:
        s = "warning";
        break;
    case kError:
        s = "error";
        break;
    case kFatal:
        s = "fatal";
        break;
    default:
        qDebug() << "Wrong sentry log level, default to error.";
        s = "error";
        break;
    }

    return s;
}
<|endoftext|>


<commit_before><commit_msg>Inserting ProtocolDispatcher::dispatch() to main() as entry point.<commit_after><|endoftext|>


<commit_before>#pragma once

#include <string>

#include <memory>
#include <mutex>
#include <tuple>

#include "balancer.hpp"
#include "connection.hpp"
#include "log.hpp"
#include "pool.hpp"
#include "resolver.hpp"
#include "result.hpp"
#include "request/info.hpp"
#include "settings.hpp"

namespace elasticsearch {

void nullcb() {}

template<class Action> struct error_handler_t;
template<class Action> struct request_watcher_t;

class http_transport_t {
public:
    typedef blackhole::synchronized<blackhole::logger_base_t> logger_type;

    typedef boost::asio::io_service loop_type;
    typedef http_connection_t connection_type;
    typedef pool_t<connection_type> pool_type;
    typedef pool_type::endpoint_type endpoint_type;

    template<class Action> friend struct error_handler_t;
    template<class Action> friend struct request_watcher_t;

private:
    settings_t settings;

    loop_type& loop;
    logger_type& log;

    pool_type pool;
    std::unique_ptr<balancing::strategy<pool_type>> balancer;
    urlfetcher_t urlfetcher;
public:
    http_transport_t(settings_t settings, loop_type& loop, logger_type& log) :
        settings(settings),
        loop(loop),
        log(log),
        balancer(new balancing::round_robin<pool_type>()),
        urlfetcher(loop)
    {}

    void add_nodes(const std::vector<endpoint_type>& endpoints) {
        for (auto it = endpoints.begin(); it != endpoints.end(); ++it) {
            add_node(*it);
        }
    }

    void add_node(const endpoint_type& endpoint) {
        boost::system::error_code ec;
        auto address = endpoint.address().to_string(ec);
        if (ec) {
            LOG(log, "can't add node endpoint '%s': %s", endpoint, ec.message());
            return;
        }

        LOG(log, "adding '%s:%d' to the pool ...", address, endpoint.port());
        bool inserted;
        std::tie(std::ignore, inserted) = pool.insert(
            endpoint, std::make_shared<connection_type>(endpoint, urlfetcher, log)
        );

        if (!inserted) {
            LOG(log, "adding endpoint to the pool is rejected - already exists");
            return;
        }
    }

    void remove_node(const endpoint_type& endpoint) {
        LOG(log, "removing '%s' from the pool ...", endpoint);
        pool.remove(endpoint);
    }

    void sniff() {
        sniff(&nullcb);
    }

    void sniff(std::function<void()>&& then) {
        LOG(log, "sniffing nodes info ...");
        auto callback = std::bind(
            &http_transport_t::on_sniff, this, std::placeholders::_1, then
        );
        perform(actions::nodes_info_t(), callback);
    }

    template<class Action>
    void perform(Action&& action,
                 typename callback<Action>::type callback,
                 int attempt = 1) {
        typedef typename Action::result_type result_type;

        BOOST_ASSERT(balancer);

        LOG(log, "performing '%s' request [attempt %d from %d] ...",
            action.name(), attempt, settings.retries);
        if (attempt > settings.retries) {
            LOG(log, "failed: too many attempts done");
            loop.post(
                std::bind(
                    callback,
                    result_type(error_t(generic_error_t("too many attempts")))
                )
            );
            return;
        }

        auto connection = balancer->next(pool);
        if (!connection) {
            LOG(log, "failed: no connections left");
            loop.post(
                std::bind(
                    callback,
                    result_type(error_t(generic_error_t("no connections left")))
                )
            );
            return;
        }

        LOG(log, "balancing at %s", connection->endpoint());
        request_watcher_t<Action> watcher {
            *this, action, callback, ++attempt
        };
        connection->perform(std::move(action), watcher);
    }

private:
    void on_sniff(result_t<response::nodes_info_t>::type&& result,
                  std::function<void()> next) {
        if (auto* info = boost::get<response::nodes_info_t>(&result)) {
            LOG(log, "successfully sniffed %d node%s",
                info->nodes.size(),
                info->nodes.size() > 1 ? "s" : ""
            );

            std::set<std::string> addresses;
            const auto& nodes = info->nodes;
            for (auto it = nodes.begin(); it != nodes.end(); ++it) {
                const response::node_t& node = it->second;
                extract_addresses(addresses, node.addresses);
            }

            typedef boost::asio::ip::tcp protocol_type;
            std::vector<endpoint_type> endpoints;
            for (auto it = addresses.begin(); it != addresses.end(); ++it) {
                try {
                    endpoints.push_back(
                        resolver<protocol_type>::resolve(*it, loop)
                    );
                } catch (const std::exception& err) {
                    LOG(log, "failed to resolve %s address: %s", *it, err.what());
                }
            }

            add_nodes(endpoints);
        }

        next();
    }

    const std::string INET_ADDR_PREFIX = "inet[";
    const std::string INET_ADDR_SUFFIX = "]";
    void extract_addresses(std::set<std::string>& result,
                           const response::node_t::addresses_type& addresses) const {
        auto it = addresses.find("http");
        if (it == addresses.end()) {
            return;
        }

        const std::string& address = it->second;
        if (boost::algorithm::starts_with(address, INET_ADDR_PREFIX)) {
            const std::string& parsed = address.substr(
                INET_ADDR_PREFIX.size(),
                address.size() -
                    INET_ADDR_PREFIX.size() -
                    INET_ADDR_SUFFIX.size()
            );
            result.insert(parsed);
        } else {
            LOG(log, "unknown address type: %s", address);
        }
    }
};

template<class Watcher>
struct error_handler_t : public boost::static_visitor<> {
    typedef Watcher watcher_type;

    const watcher_type& watcher;
    http_transport_t& transport;

    error_handler_t(const watcher_type& watcher, http_transport_t& transport) :
        watcher(watcher),
        transport(transport)
    {}

    void operator()(const connection_error_t& err) {
        LOG(transport.log, "request failed with error: %s", err.reason);

        transport.remove_node(err.endpoint);
        if (transport.settings.sniffer.when.error) {
            LOG(transport.log,
                "sniff.on.error is true - preparing to update nodes list");
            transport.sniff(watcher);
            return;
        }
    }

    void operator()(const generic_error_t& err) {
        LOG(transport.log, "request failed with error: %s", err.reason);
    }
};

template<class Action>
struct request_watcher_t {
    typedef Action action_type;
    typedef request_watcher_t<action_type> this_type;
    typedef typename action_type::result_type result_type;
    typedef typename callback<action_type>::type callback_type;

    http_transport_t& transport;
    const action_type action;
    const callback_type callback;
    const int attempt;

    template<class Result = result_type>
    typename std::enable_if<
        !std::is_same<Result, result_t<response::nodes_info_t>::type>::value
    >::type
    operator()(result_type&& result) const {
        if (error_t* error = boost::get<error_t>(&result)) {
            auto visitor = error_handler_t<this_type>(*this, transport);
            boost::apply_visitor(visitor, *error);
        }

        callback(std::move(result));
    }

    template<class Result = result_type>
    typename std::enable_if<
        std::is_same<Result, result_t<response::nodes_info_t>::type>::value
    >::type
    operator()(result_t<response::nodes_info_t>::type&& result) const {
        callback(std::move(result));
    }

    void operator()() {
        transport.perform(std::move(action), callback, attempt);
    }
};

} // namespace elasticsearch

<commit_msg>[Elasticsearch] Moving some constants to the global scope.<commit_after>#pragma once

#include <string>

#include <memory>
#include <mutex>
#include <tuple>

#include "balancer.hpp"
#include "connection.hpp"
#include "log.hpp"
#include "pool.hpp"
#include "resolver.hpp"
#include "result.hpp"
#include "request/info.hpp"
#include "settings.hpp"

namespace elasticsearch {

void nullcb() {}

template<class Action> struct error_handler_t;
template<class Action> struct request_watcher_t;

const std::string INET_ADDR_PREFIX = "inet[";
const std::string INET_ADDR_SUFFIX = "]";

class http_transport_t {
public:
    typedef blackhole::synchronized<blackhole::logger_base_t> logger_type;

    typedef boost::asio::io_service loop_type;
    typedef http_connection_t connection_type;
    typedef pool_t<connection_type> pool_type;
    typedef pool_type::endpoint_type endpoint_type;

    template<class Action> friend struct error_handler_t;
    template<class Action> friend struct request_watcher_t;

private:
    settings_t settings;

    loop_type& loop;
    logger_type& log;

    pool_type pool;
    std::unique_ptr<balancing::strategy<pool_type>> balancer;
    urlfetcher_t urlfetcher;
public:
    http_transport_t(settings_t settings, loop_type& loop, logger_type& log) :
        settings(settings),
        loop(loop),
        log(log),
        balancer(new balancing::round_robin<pool_type>()),
        urlfetcher(loop)
    {}

    void add_nodes(const std::vector<endpoint_type>& endpoints) {
        for (auto it = endpoints.begin(); it != endpoints.end(); ++it) {
            add_node(*it);
        }
    }

    void add_node(const endpoint_type& endpoint) {
        boost::system::error_code ec;
        auto address = endpoint.address().to_string(ec);
        if (ec) {
            LOG(log, "can't add node endpoint '%s': %s", endpoint, ec.message());
            return;
        }

        LOG(log, "adding '%s:%d' to the pool ...", address, endpoint.port());
        bool inserted;
        std::tie(std::ignore, inserted) = pool.insert(
            endpoint, std::make_shared<connection_type>(endpoint, urlfetcher, log)
        );

        if (!inserted) {
            LOG(log, "adding endpoint to the pool is rejected - already exists");
            return;
        }
    }

    void remove_node(const endpoint_type& endpoint) {
        LOG(log, "removing '%s' from the pool ...", endpoint);
        pool.remove(endpoint);
    }

    void sniff() {
        sniff(&nullcb);
    }

    void sniff(std::function<void()>&& then) {
        LOG(log, "sniffing nodes info ...");
        auto callback = std::bind(
            &http_transport_t::on_sniff, this, std::placeholders::_1, then
        );
        perform(actions::nodes_info_t(), callback);
    }

    template<class Action>
    void perform(Action&& action,
                 typename callback<Action>::type callback,
                 int attempt = 1) {
        typedef typename Action::result_type result_type;

        BOOST_ASSERT(balancer);

        LOG(log, "performing '%s' request [attempt %d from %d] ...",
            action.name(), attempt, settings.retries);
        if (attempt > settings.retries) {
            LOG(log, "failed: too many attempts done");
            loop.post(
                std::bind(
                    callback,
                    result_type(error_t(generic_error_t("too many attempts")))
                )
            );
            return;
        }

        auto connection = balancer->next(pool);
        if (!connection) {
            LOG(log, "failed: no connections left");
            loop.post(
                std::bind(
                    callback,
                    result_type(error_t(generic_error_t("no connections left")))
                )
            );
            return;
        }

        LOG(log, "balancing at %s", connection->endpoint());
        request_watcher_t<Action> watcher {
            *this, action, callback, ++attempt
        };
        connection->perform(std::move(action), watcher);
    }

private:
    void on_sniff(result_t<response::nodes_info_t>::type&& result,
                  std::function<void()> next) {
        if (auto* info = boost::get<response::nodes_info_t>(&result)) {
            LOG(log, "successfully sniffed %d node%s",
                info->nodes.size(),
                info->nodes.size() > 1 ? "s" : ""
            );

            std::set<std::string> addresses;
            const auto& nodes = info->nodes;
            for (auto it = nodes.begin(); it != nodes.end(); ++it) {
                const response::node_t& node = it->second;
                extract_addresses(addresses, node.addresses);
            }

            typedef boost::asio::ip::tcp protocol_type;
            std::vector<endpoint_type> endpoints;
            for (auto it = addresses.begin(); it != addresses.end(); ++it) {
                try {
                    endpoints.push_back(
                        resolver<protocol_type>::resolve(*it, loop)
                    );
                } catch (const std::exception& err) {
                    LOG(log, "failed to resolve %s address: %s", *it, err.what());
                }
            }

            add_nodes(endpoints);
        }

        next();
    }

    void extract_addresses(std::set<std::string>& result,
                           const response::node_t::addresses_type& addresses) const {
        auto it = addresses.find("http");
        if (it == addresses.end()) {
            return;
        }

        const std::string& address = it->second;
        if (boost::algorithm::starts_with(address, INET_ADDR_PREFIX)) {
            const std::string& parsed = address.substr(
                INET_ADDR_PREFIX.size(),
                address.size() -
                    INET_ADDR_PREFIX.size() -
                    INET_ADDR_SUFFIX.size()
            );
            result.insert(parsed);
        } else {
            LOG(log, "unknown address type: %s", address);
        }
    }
};

template<class Watcher>
struct error_handler_t : public boost::static_visitor<> {
    typedef Watcher watcher_type;

    const watcher_type& watcher;
    http_transport_t& transport;

    error_handler_t(const watcher_type& watcher, http_transport_t& transport) :
        watcher(watcher),
        transport(transport)
    {}

    void operator()(const connection_error_t& err) {
        LOG(transport.log, "request failed with error: %s", err.reason);

        transport.remove_node(err.endpoint);
        if (transport.settings.sniffer.when.error) {
            LOG(transport.log,
                "sniff.on.error is true - preparing to update nodes list");
            transport.sniff(watcher);
            return;
        }
    }

    void operator()(const generic_error_t& err) {
        LOG(transport.log, "request failed with error: %s", err.reason);
    }
};

template<class Action>
struct request_watcher_t {
    typedef Action action_type;
    typedef request_watcher_t<action_type> this_type;
    typedef typename action_type::result_type result_type;
    typedef typename callback<action_type>::type callback_type;

    http_transport_t& transport;
    const action_type action;
    const callback_type callback;
    const int attempt;

    template<class Result = result_type>
    typename std::enable_if<
        !std::is_same<Result, result_t<response::nodes_info_t>::type>::value
    >::type
    operator()(result_type&& result) const {
        if (error_t* error = boost::get<error_t>(&result)) {
            auto visitor = error_handler_t<this_type>(*this, transport);
            boost::apply_visitor(visitor, *error);
        }

        callback(std::move(result));
    }

    template<class Result = result_type>
    typename std::enable_if<
        std::is_same<Result, result_t<response::nodes_info_t>::type>::value
    >::type
    operator()(result_t<response::nodes_info_t>::type&& result) const {
        callback(std::move(result));
    }

    void operator()() {
        transport.perform(std::move(action), callback, attempt);
    }
};

} // namespace elasticsearch

<|endoftext|>


<commit_before><commit_msg>pnc_map: handle edge case in heuristic projection<commit_after><|endoftext|>


<commit_before><commit_msg>Implement KRubyArray.collect and KRubyArray.map.<commit_after><|endoftext|>


<commit_before>/** Copyright (C) 2016 European Spallation Source ERIC */

#include <prototype2/common/DataSave.h>
#include <RunSpecParse.h>
#include <test/TestBase.h>
#include <cstring>

std::string filename{"deleteme.json"};

std::string runspecjson = " \
{ \n\
  \"test\" :\n\
    [ \
      {\"id\": 42,  \"dir\": \"mydir\",  \"prefix\": \"myprefix\",  \"postfix\": \"mypostfix\", \"start\": 1, \"end\":   999, \"thresh\": 124} \n\
    ] \n\
}";

std::string invalidjson = "{ \"this is not valid json\" }";

class RunSpecParseTest : public TestBase {
protected:
};

/** Test cases below */

TEST_F(RunSpecParseTest, ParseJson) {
  DataSave tempfile(filename, (void *)runspecjson.c_str(), runspecjson.size());
  RunSpecParse runspec(filename);

  auto runs = runspec.getruns("test", "basedir", "outputdir", 1, 200);

  ASSERT_EQ(1, runs.size());
  ASSERT_EQ(runs.at(0)->dir_, "basedir/mydir");
  ASSERT_EQ(runs.at(0)->ofile_, "outputdir/test_42");
  ASSERT_EQ(runs.at(0)->prefix_, "myprefix");
  ASSERT_EQ(runs.at(0)->postfix_, "mypostfix");
  ASSERT_EQ(runs.at(0)->start_, 1);
  ASSERT_EQ(runs.at(0)->end_, 999);
}

TEST_F(RunSpecParseTest, InvalidJson) {
  DataSave tempfile(filename, (void *)invalidjson.c_str(), invalidjson.size());
  RunSpecParse runspec(filename);

  // DeathTest
  ASSERT_EXIT(runspec.getruns("test", "basedir", "outputdir", 1, 200), ::testing::ExitedWithCode(1), "");
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>using new c++ string literal<commit_after>/** Copyright (C) 2016 European Spallation Source ERIC */

#include <prototype2/common/DataSave.h>
#include <RunSpecParse.h>
#include <test/TestBase.h>
#include <cstring>

std::string filename{"deleteme.json"};

std::string runspecjson = R"(
{
  "test" :
    [
      {"id": 42,  "dir": "mydir",  "prefix": "myprefix",  "postfix": "mypostfix", "start": 1, "end":   999, "thresh": 124}
    ]
})";

std::string invalidjson = R"({ "this is not valid json" })";

class RunSpecParseTest : public TestBase {
protected:
};

/** Test cases below */

TEST_F(RunSpecParseTest, ParseJson) {
  DataSave tempfile(filename, (void *)runspecjson.c_str(), runspecjson.size());
  RunSpecParse runspec(filename);

  auto runs = runspec.getruns("test", "basedir", "outputdir", 1, 200);

  ASSERT_EQ(1, runs.size());
  ASSERT_EQ(runs.at(0)->dir_, "basedir/mydir");
  ASSERT_EQ(runs.at(0)->ofile_, "outputdir/test_42");
  ASSERT_EQ(runs.at(0)->prefix_, "myprefix");
  ASSERT_EQ(runs.at(0)->postfix_, "mypostfix");
  ASSERT_EQ(runs.at(0)->start_, 1);
  ASSERT_EQ(runs.at(0)->end_, 999);
}

TEST_F(RunSpecParseTest, InvalidJson) {
  DataSave tempfile(filename, (void *)invalidjson.c_str(), invalidjson.size());
  RunSpecParse runspec(filename);

  // DeathTest
  ASSERT_EXIT(runspec.getruns("test", "basedir", "outputdir", 1, 200), ::testing::ExitedWithCode(1), "");
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>