Program Listing for File gtest_quickstart.hpp

Return to documentation for file (/tmp/ws/src/osrf_testing_tools_cpp/osrf_testing_tools_cpp/include/osrf_testing_tools_cpp/memory_tools/gtest_quickstart.hpp)

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

#ifndef OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__GTEST_QUICKSTART_HPP_
#define OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__GTEST_QUICKSTART_HPP_

#include <map>
#include <string>
#include <utility>

#include <gtest/gtest.h>

#include "./memory_tools.hpp"
#include "./testing_helpers.hpp"


namespace osrf_testing_tools_cpp
{
namespace memory_tools
{

class QuickstartConfiguration
{
public:
  using ConfigMap = std::map<
    std::string,  // one of malloc, realloc, calloc, free
    std::pair<
      std::string,  // error message or "" for default
      bool  // whether or not the backtrace should be printed
    >
  >;

  QuickstartConfiguration()
  : config_({
    {"malloc", {"unexpected call to malloc", false}},
    {"realloc", {"unexpected call to realloc", false}},
    {"calloc", {"unexpected call to calloc", false}},
    {"free", {"unexpected call to free", false}},
  })
  {}

  explicit
  QuickstartConfiguration(bool should_print_backtrace)
  : QuickstartConfiguration()
  {
    for (auto & kv_pair : config_) {
      kv_pair.second.second = should_print_backtrace;
    }
  }

  explicit
  QuickstartConfiguration(const ConfigMap & config)
  : QuickstartConfiguration()
  {
    for (const auto & kv_pair : config) {
      if (config_.count(kv_pair.first) == 0) {
        throw std::runtime_error("unexpected QuickstartConfiguration key '" + kv_pair.first + "'");
      }
      config_[kv_pair.first] = kv_pair.second;
    }
  }

  explicit
  QuickstartConfiguration(const std::map<std::string, std::string> & config_with_error_message)
  : QuickstartConfiguration()
  {
    for (const auto & kv_pair : config_with_error_message) {
      if (config_.count(kv_pair.first) == 0) {
        throw std::runtime_error("unexpected QuickstartConfiguration key '" + kv_pair.first + "'");
      }
      config_[kv_pair.first] = {kv_pair.second, config_[kv_pair.first].second};
    }
  }

  explicit
  QuickstartConfiguration(const std::map<std::string, bool> & config_with_error_message)
  : QuickstartConfiguration()
  {
    for (const auto & kv_pair : config_with_error_message) {
      if (config_.count(kv_pair.first) == 0) {
        throw std::runtime_error("unexpected QuickstartConfiguration key '" + kv_pair.first + "'");
      }
      config_[kv_pair.first] = {config_[kv_pair.first].first, kv_pair.second};
    }
  }

  const ConfigMap &
  get_config() const
  {
    return config_;
  }

private:
  ConfigMap config_;
};


template<typename ...Args>
bool
quickstart_gtest_setup(Args &&... args)
{
  QuickstartConfiguration quickstart_config(std::forward<Args>(args)...);
  const auto & config_map = quickstart_config.get_config();
  osrf_testing_tools_cpp::memory_tools::initialize();

  auto callback_factory = [](const std::string & message, bool should_print_backtrace) {
    return
      [message, should_print_backtrace]
      (osrf_testing_tools_cpp::memory_tools::MemoryToolsService & service) {
        ADD_FAILURE() << message;
          // this will cause a bracktrace to be printed for each unexpected malloc
          if (should_print_backtrace) {
            service.print_backtrace();
          }
      };
  };

  for (const auto & kv_pair : config_map) {
    if ("malloc" == kv_pair.first) {
      osrf_testing_tools_cpp::memory_tools::on_unexpected_malloc(
        callback_factory(kv_pair.second.first, kv_pair.second.second));
    } else if ("realloc" == kv_pair.first) {
      osrf_testing_tools_cpp::memory_tools::on_unexpected_realloc(
        callback_factory(kv_pair.second.first, kv_pair.second.second));
    } else if ("calloc" == kv_pair.first) {
      osrf_testing_tools_cpp::memory_tools::on_unexpected_calloc(
        callback_factory(kv_pair.second.first, kv_pair.second.second));
    } else if ("free" == kv_pair.first) {
      osrf_testing_tools_cpp::memory_tools::on_unexpected_free(
        callback_factory(kv_pair.second.first, kv_pair.second.second));
    } else {
      throw std::runtime_error("unexpected config key '" + kv_pair.first + "'");
    }
  }
  osrf_testing_tools_cpp::memory_tools::enable_monitoring();

  return osrf_testing_tools_cpp::memory_tools::is_working();
}

inline
void
quickstart_gtest_teardown()
{
  osrf_testing_tools_cpp::memory_tools::disable_monitoring();
  osrf_testing_tools_cpp::memory_tools::uninitialize();
}

class ScopedQuickstartGtest
{
public:
  template<typename... Args>
  explicit
  ScopedQuickstartGtest(Args &&... args)
  : is_working_(quickstart_gtest_setup(std::forward<Args>(args)...))
  {}

  virtual
  ~ScopedQuickstartGtest()
  {
    quickstart_gtest_teardown();
  }

  bool
  memory_tools_is_working() const
  {
    return is_working_;
  }

private:
  bool is_working_;
};

}  // namespace memory_tools
}  // namespace osrf_testing_tools_cpp

#endif  // OSRF_TESTING_TOOLS_CPP__MEMORY_TOOLS__GTEST_QUICKSTART_HPP_