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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkRenderingManager.h"
#include "mitkPlanePositionManager.h"
#include <mitkCoreDataNodeReader.h>
#include <mitkStandardFileLocations.h>
//#include <mitkShaderRepository.h>
#include <mitkPropertyAliases.h>
#include <mitkPropertyDescriptions.h>
#include <mitkPropertyExtensions.h>
#include <mitkPropertyFilters.h>
#include <mitkIOUtil.h>

#include <usModuleInitialization.h>
#include <usModuleActivator.h>
#include <usModuleContext.h>
#include <usModuleSettings.h>
#include <usModuleEvent.h>
#include <usModule.h>
#include <usModuleResource.h>
#include <usModuleResourceStream.h>

void HandleMicroServicesMessages(us::MsgType type, const char* msg)
{
  switch (type)
  {
  case us::DebugMsg:
    MITK_DEBUG << msg;
    break;
  case us::InfoMsg:
    MITK_INFO << msg;
    break;
  case us::WarningMsg:
    MITK_WARN << msg;
    break;
  case us::ErrorMsg:
    MITK_ERROR << msg;
    break;
  }
}

void AddMitkAutoLoadPaths(const std::string& programPath)
{
  us::ModuleSettings::AddAutoLoadPath(programPath);
#ifdef __APPLE__
  // Walk up three directories since that is where the .dylib files are located
  // for build trees.
  std::string additionalPath = programPath;
  bool addPath = true;
  for(int i = 0; i < 3; ++i)
  {
    std::size_t index = additionalPath.find_last_of('/');
    if (index != std::string::npos)
    {
      additionalPath = additionalPath.substr(0, index);
    }
    else
    {
      addPath = false;
      break;
    }
  }
  if (addPath)
  {
    us::ModuleSettings::AddAutoLoadPath(additionalPath);
  }
#endif
}

/*
 * This is the module activator for the "Mitk" module. It registers core services
 * like ...
 */
class MitkCoreActivator : public us::ModuleActivator
{
public:

  void Load(us::ModuleContext* context)
  {
    // Handle messages from CppMicroServices
    us::installMsgHandler(HandleMicroServicesMessages);

    // Add the current application directory to the auto-load paths.
    // This is useful for third-party executables.
    std::string programPath = mitk::IOUtil::GetProgramPath();
    if (programPath.empty())
    {
      MITK_WARN << "Could not get the program path.";
    }
    else
    {
      AddMitkAutoLoadPaths(programPath);
    }

    //m_RenderingManager = mitk::RenderingManager::New();
    //context->RegisterService<mitk::RenderingManager>(renderingManager.GetPointer());
    m_PlanePositionManager.reset(new mitk::PlanePositionManagerService);
    context->RegisterService<mitk::PlanePositionManagerService>(m_PlanePositionManager.get());

    m_CoreDataNodeReader.reset(new mitk::CoreDataNodeReader);
    context->RegisterService<mitk::IDataNodeReader>(m_CoreDataNodeReader.get());

    m_PropertyAliases.reset(new mitk::PropertyAliases);
    context->RegisterService<mitk::IPropertyAliases>(m_PropertyAliases.get());

    m_PropertyDescriptions.reset(new mitk::PropertyDescriptions);
    context->RegisterService<mitk::IPropertyDescriptions>(m_PropertyDescriptions.get());

    m_PropertyExtensions.reset(new mitk::PropertyExtensions);
    context->RegisterService<mitk::IPropertyExtensions>(m_PropertyExtensions.get());

    m_PropertyFilters.reset(new mitk::PropertyFilters);
    context->RegisterService<mitk::IPropertyFilters>(m_PropertyFilters.get());

    context->AddModuleListener(this, &MitkCoreActivator::HandleModuleEvent);

    /*
    There IS an option to exchange ALL vtkTexture instances against vtkNeverTranslucentTextureFactory.
    This code is left here as a reminder, just in case we might need to do that some time.

    vtkNeverTranslucentTextureFactory* textureFactory = vtkNeverTranslucentTextureFactory::New();
    vtkObjectFactory::RegisterFactory( textureFactory );
    textureFactory->Delete();
    */
  }

  void Unload(us::ModuleContext* )
  {
    // The mitk::ModuleContext* argument of the Unload() method
    // will always be 0 for the Mitk library. It makes no sense
    // to use it at this stage anyway, since all libraries which
    // know about the module system have already been unloaded.
  }

private:

  void HandleModuleEvent(const us::ModuleEvent moduleEvent);

  std::map<long, std::vector<int> > moduleIdToShaderIds;

  //mitk::RenderingManager::Pointer m_RenderingManager;
  std::auto_ptr<mitk::PlanePositionManagerService> m_PlanePositionManager;
  std::auto_ptr<mitk::CoreDataNodeReader> m_CoreDataNodeReader;
  std::auto_ptr<mitk::PropertyAliases> m_PropertyAliases;
  std::auto_ptr<mitk::PropertyDescriptions> m_PropertyDescriptions;
  std::auto_ptr<mitk::PropertyExtensions> m_PropertyExtensions;
  std::auto_ptr<mitk::PropertyFilters> m_PropertyFilters;
};

void MitkCoreActivator::HandleModuleEvent(const us::ModuleEvent moduleEvent)
{
  if (moduleEvent.GetType() == us::ModuleEvent::LOADED)
  {
    // search and load shader files
    std::vector<us::ModuleResource> shaderResoruces =
        moduleEvent.GetModule()->FindResources("Shaders", "*.xml", true);
    for (std::vector<us::ModuleResource>::iterator i = shaderResoruces.begin();
         i != shaderResoruces.end(); ++i)
    {
      if (*i)
      {
        us::ModuleResourceStream rs(*i);
//        int id = m_ShaderRepository->LoadShader(rs, i->GetBaseName());
//        if (id >= 0)
//        {
//          moduleIdToShaderIds[moduleEvent.GetModule()->GetModuleId()].push_back(id);
//        }
      }
    }
  }
  else if (moduleEvent.GetType() == us::ModuleEvent::UNLOADED)
  {
    std::map<long, std::vector<int> >::iterator shaderIdsIter =
        moduleIdToShaderIds.find(moduleEvent.GetModule()->GetModuleId());
    if (shaderIdsIter != moduleIdToShaderIds.end())
    {
//      for (std::vector<int>::iterator idIter = shaderIdsIter->second.begin();
//           idIter != shaderIdsIter->second.end(); ++idIter)
//      {
//        m_ShaderRepository->UnloadShader(*idIter);
//      }
//      moduleIdToShaderIds.erase(shaderIdsIter);
    }
  }

}

US_EXPORT_MODULE_ACTIVATOR(Mitk, MitkCoreActivator)

// Call CppMicroservices initialization code at the end of the file.
// This especially ensures that VTK object factories have already
// been registered (VTK initialization code is injected by implicitly
// include VTK header files at the top of this file).
US_INITIALIZE_MODULE("Mitk", "Mitk")
<commit_msg>Track IShaderRepository services and manager shader resources.<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkRenderingManager.h"
#include "mitkPlanePositionManager.h"
#include <mitkCoreDataNodeReader.h>
#include <mitkStandardFileLocations.h>
#include <mitkIShaderRepository.h>
#include <mitkPropertyAliases.h>
#include <mitkPropertyDescriptions.h>
#include <mitkPropertyExtensions.h>
#include <mitkPropertyFilters.h>
#include <mitkIOUtil.h>

#include <usGetModuleContext.h>
#include <usModuleInitialization.h>
#include <usModuleActivator.h>
#include <usModuleContext.h>
#include <usModuleSettings.h>
#include <usModuleEvent.h>
#include <usModule.h>
#include <usModuleResource.h>
#include <usModuleResourceStream.h>
#include <usServiceTracker.h>

void HandleMicroServicesMessages(us::MsgType type, const char* msg)
{
  switch (type)
  {
  case us::DebugMsg:
    MITK_DEBUG << msg;
    break;
  case us::InfoMsg:
    MITK_INFO << msg;
    break;
  case us::WarningMsg:
    MITK_WARN << msg;
    break;
  case us::ErrorMsg:
    MITK_ERROR << msg;
    break;
  }
}

void AddMitkAutoLoadPaths(const std::string& programPath)
{
  us::ModuleSettings::AddAutoLoadPath(programPath);
#ifdef __APPLE__
  // Walk up three directories since that is where the .dylib files are located
  // for build trees.
  std::string additionalPath = programPath;
  bool addPath = true;
  for(int i = 0; i < 3; ++i)
  {
    std::size_t index = additionalPath.find_last_of('/');
    if (index != std::string::npos)
    {
      additionalPath = additionalPath.substr(0, index);
    }
    else
    {
      addPath = false;
      break;
    }
  }
  if (addPath)
  {
    us::ModuleSettings::AddAutoLoadPath(additionalPath);
  }
#endif
}

class ShaderRepositoryTracker : public us::ServiceTracker<mitk::IShaderRepository>
{

public:

  ShaderRepositoryTracker()
    : Superclass(us::GetModuleContext())
  {
  }

  virtual void Close()
  {
    us::GetModuleContext()->RemoveModuleListener(this, &ShaderRepositoryTracker::HandleModuleEvent);
    Superclass::Close();
  }

  virtual void Open()
  {
    us::GetModuleContext()->AddModuleListener(this, &ShaderRepositoryTracker::HandleModuleEvent);
    Superclass::Open();
  }

private:

  typedef us::ServiceTracker<mitk::IShaderRepository> Superclass;

  TrackedType AddingService(const ServiceReferenceType &reference)
  {
    mitk::IShaderRepository* shaderRepo = Superclass::AddingService(reference);
    if (shaderRepo)
    {
      // Add all existing shaders from modules to the new shader repository.
      // If the shader repository is registered in a modules activator, the
      // GetLoadedModules() function call below will also return the module
      // which is currently registering the repository. The HandleModuleEvent
      // method contains code to avoid double registrations due to a fired
      // ModuleEvent::LOADED event after the activators Load() method finished.
      std::vector<us::Module*> modules = us::ModuleRegistry::GetLoadedModules();
      for (std::vector<us::Module*>::const_iterator iter = modules.begin(),
           endIter = modules.end(); iter != endIter; ++iter)
      {
        this->AddModuleShaderToRepository(*iter, shaderRepo);
      }

      m_ShaderRepositories.push_back(shaderRepo);
    }
    return shaderRepo;
  }

  void RemovedService(const ServiceReferenceType& /*reference*/, TrackedType tracked)
  {
    m_ShaderRepositories.erase(std::remove(m_ShaderRepositories.begin(), m_ShaderRepositories.end(), tracked),
                               m_ShaderRepositories.end());
  }

  void HandleModuleEvent(const us::ModuleEvent moduleEvent)
  {
    if (moduleEvent.GetType() == us::ModuleEvent::LOADED)
    {
      std::vector<mitk::IShaderRepository*> shaderRepos;
      for (std::map<mitk::IShaderRepository*, std::map<long, std::vector<int> > >::const_iterator shaderMapIter = m_ModuleIdToShaderIds.begin(),
           shaderMapEndIter = m_ModuleIdToShaderIds.end(); shaderMapIter != shaderMapEndIter; ++shaderMapIter)
      {
        if (shaderMapIter->second.find(moduleEvent.GetModule()->GetModuleId()) == shaderMapIter->second.end())
        {
          shaderRepos.push_back(shaderMapIter->first);
        }
      }
      AddModuleShadersToRepositories(moduleEvent.GetModule(), shaderRepos);
    }
    else if (moduleEvent.GetType() == us::ModuleEvent::UNLOADED)
    {
      RemoveModuleShadersFromRepositories(moduleEvent.GetModule(), m_ShaderRepositories);
    }
  }

  void AddModuleShadersToRepositories(us::Module* module, const std::vector<mitk::IShaderRepository*>& shaderRepos)
  {
    // search and load shader files
    std::vector<us::ModuleResource> shaderResources = module->FindResources("Shaders", "*.xml", true);
    for (std::vector<us::ModuleResource>::iterator i = shaderResources.begin();
         i != shaderResources.end(); ++i)
    {
      if (*i)
      {
        us::ModuleResourceStream rs(*i);
        for (std::vector<mitk::IShaderRepository*>::const_iterator shaderRepoIter = shaderRepos.begin(),
             shaderRepoEndIter = shaderRepos.end(); shaderRepoIter != shaderRepoEndIter; ++shaderRepoIter)
        {
          int id = (*shaderRepoIter)->LoadShader(rs, i->GetBaseName());
          if (id >= 0)
          {
            m_ModuleIdToShaderIds[*shaderRepoIter][module->GetModuleId()].push_back(id);
          }
        }
        rs.seekg(0, std::ios_base::beg);
      }
    }
  }

  void AddModuleShaderToRepository(us::Module* module, mitk::IShaderRepository* shaderRepo)
  {
    std::vector<mitk::IShaderRepository*> shaderRepos;
    shaderRepos.push_back(shaderRepo);
    this->AddModuleShadersToRepositories(module, shaderRepos);
  }

  void RemoveModuleShadersFromRepositories(us::Module* module,
                                           const std::vector<mitk::IShaderRepository*>& shaderRepos)
  {
    for (std::vector<mitk::IShaderRepository*>::const_iterator shaderRepoIter = shaderRepos.begin(),
         shaderRepoEndIter = shaderRepos.end(); shaderRepoIter != shaderRepoEndIter; ++shaderRepoIter)
    {
      std::map<long, std::vector<int> >& moduleIdToShaderIds = m_ModuleIdToShaderIds[*shaderRepoIter];
      std::map<long, std::vector<int> >::iterator shaderIdsIter =
        moduleIdToShaderIds.find(module->GetModuleId());
      if (shaderIdsIter != moduleIdToShaderIds.end())
      {
        for (std::vector<int>::iterator idIter = shaderIdsIter->second.begin();
             idIter != shaderIdsIter->second.end(); ++idIter)
        {
          (*shaderRepoIter)->UnloadShader(*idIter);
        }
        moduleIdToShaderIds.erase(shaderIdsIter);
      }
    }
  }

private:

  // Maps to each shader repository a map containing module ids and related
  // shader registration ids
  std::map<mitk::IShaderRepository*, std::map<long, std::vector<int> > > m_ModuleIdToShaderIds;
  std::vector<mitk::IShaderRepository*> m_ShaderRepositories;
};

/*
 * This is the module activator for the "Mitk" module. It registers core services
 * like ...
 */
class MitkCoreActivator : public us::ModuleActivator
{
public:

  void Load(us::ModuleContext* context)
  {
    // Handle messages from CppMicroServices
    us::installMsgHandler(HandleMicroServicesMessages);

    // Add the current application directory to the auto-load paths.
    // This is useful for third-party executables.
    std::string programPath = mitk::IOUtil::GetProgramPath();
    if (programPath.empty())
    {
      MITK_WARN << "Could not get the program path.";
    }
    else
    {
      AddMitkAutoLoadPaths(programPath);
    }

    //m_RenderingManager = mitk::RenderingManager::New();
    //context->RegisterService<mitk::RenderingManager>(renderingManager.GetPointer());
    m_PlanePositionManager.reset(new mitk::PlanePositionManagerService);
    context->RegisterService<mitk::PlanePositionManagerService>(m_PlanePositionManager.get());

    m_CoreDataNodeReader.reset(new mitk::CoreDataNodeReader);
    context->RegisterService<mitk::IDataNodeReader>(m_CoreDataNodeReader.get());

    m_PropertyAliases.reset(new mitk::PropertyAliases);
    context->RegisterService<mitk::IPropertyAliases>(m_PropertyAliases.get());

    m_PropertyDescriptions.reset(new mitk::PropertyDescriptions);
    context->RegisterService<mitk::IPropertyDescriptions>(m_PropertyDescriptions.get());

    m_PropertyExtensions.reset(new mitk::PropertyExtensions);
    context->RegisterService<mitk::IPropertyExtensions>(m_PropertyExtensions.get());

    m_PropertyFilters.reset(new mitk::PropertyFilters);
    context->RegisterService<mitk::IPropertyFilters>(m_PropertyFilters.get());

    m_ShaderRepositoryTracker.Open();

    /*
    There IS an option to exchange ALL vtkTexture instances against vtkNeverTranslucentTextureFactory.
    This code is left here as a reminder, just in case we might need to do that some time.

    vtkNeverTranslucentTextureFactory* textureFactory = vtkNeverTranslucentTextureFactory::New();
    vtkObjectFactory::RegisterFactory( textureFactory );
    textureFactory->Delete();
    */
  }

  void Unload(us::ModuleContext* )
  {
    // The mitk::ModuleContext* argument of the Unload() method
    // will always be 0 for the Mitk library. It makes no sense
    // to use it at this stage anyway, since all libraries which
    // know about the module system have already been unloaded.

    m_ShaderRepositoryTracker.Close();
  }

private:

  ShaderRepositoryTracker m_ShaderRepositoryTracker;

  //mitk::RenderingManager::Pointer m_RenderingManager;
  std::auto_ptr<mitk::PlanePositionManagerService> m_PlanePositionManager;
  std::auto_ptr<mitk::CoreDataNodeReader> m_CoreDataNodeReader;
  std::auto_ptr<mitk::PropertyAliases> m_PropertyAliases;
  std::auto_ptr<mitk::PropertyDescriptions> m_PropertyDescriptions;
  std::auto_ptr<mitk::PropertyExtensions> m_PropertyExtensions;
  std::auto_ptr<mitk::PropertyFilters> m_PropertyFilters;
};

US_EXPORT_MODULE_ACTIVATOR(Mitk, MitkCoreActivator)

// Call CppMicroservices initialization code at the end of the file.
// This especially ensures that VTK object factories have already
// been registered (VTK initialization code is injected by implicitly
// include VTK header files at the top of this file).
US_INITIALIZE_MODULE("Mitk", "Mitk")
<|endoftext|>


<commit_before>//=================================================================================================
// Copyright (c) 2016, Stefan Kohlbrecher, TU Darmstadt
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Simulation, Systems Optimization and Robotics
//       group, TU Darmstadt nor the names of its contributors may be used to
//       endorse or promote products derived from this software without
//       specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//=================================================================================================

#include <ros/ros.h>
#include <grid_map_planner_lib/grid_map_planner.h>

#include <nav_msgs/OccupancyGrid.h>
#include <geometry_msgs/PoseWithCovarianceStamped.h>
#include <grid_map_ros/GridMapRosConverter.hpp>

#include <nav_msgs/Path.h>

class TestGridMapPlanner
{
public:
  TestGridMapPlanner()
  {
    ros::NodeHandle nh;

    map_sub_ = nh.subscribe("/map",10,&TestGridMapPlanner::map_cb,this);

    map_pub_ = nh.advertise<grid_map_msgs::GridMap>("/grid_map", 2, true);
    path_pub_ = nh.advertise<nav_msgs::Path>("/path", 2, true);

    goal_pose_sub_ = nh.subscribe("/goal", 2, &TestGridMapPlanner::goalPoseCallback, this);
    search_pose_sub_ = nh.subscribe("/search_pose", 2, &TestGridMapPlanner::searchPoseCallback, this);
    pose_with_cov_sub_ = nh.subscribe("/initialpose", 2, &TestGridMapPlanner::poseWithCovCallback, this);
    exploration_start_pose_sub_ = nh.subscribe("/explore_initialpose", 2, &TestGridMapPlanner::explorePoseCallback, this);
    multi_goal_start_pose_sub_ = nh.subscribe("/multi_goal_initialpose", 2, &TestGridMapPlanner::multiGoalPoseCallback, this);

  }

  void goalPoseCallback(const geometry_msgs::PoseStamped::ConstPtr& msg)
  {
    ROS_INFO("Goal pose callback");

    goal_pose = msg->pose;
    this->plan_path_to_goal();
  }

  void searchPoseCallback(const geometry_msgs::PoseStamped::ConstPtr& msg)
  {
    ROS_INFO("Search pose callback");
  }

  void poseWithCovCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg)
  {
    ROS_INFO("Start pose callback");
    start_pose = msg->pose.pose;
    this->plan_path_to_goal();
  }

  void explorePoseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg)
  {
    ROS_INFO("Explore pose callback");

    ros::WallTime start_time = ros::WallTime::now();

    nav_msgs::Path path;
    path.header.stamp = ros::Time::now();
    path.header.frame_id = "map";

    gp_.makeExplorationPlan(msg->pose.pose, path.poses);

    path_pub_.publish(path);

    grid_map_msgs::GridMap grid_map_out;
    grid_map::GridMapRosConverter::toMessage(gp_.getPlanningMap(), grid_map_out);
    std::cout << "Planning exploration took " << (ros::WallTime::now() - start_time).toSec() * 1000 << " ms\n";

    //grid_map::GridMapRosConverter::toMessage(map, grid_map_out);
    map_pub_.publish(grid_map_out);
  }

  void multiGoalPoseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg)
  {
    ROS_INFO("Multi goal pose callback");

    ros::WallTime start_time = ros::WallTime::now();

    nav_msgs::Path path;
    path.header.stamp = ros::Time::now();
    path.header.frame_id = "map";

    std::vector<boost::shared_ptr<grid_map_planner_goal_types::MapGoalBase> > map_goals;

    geometry_msgs::Point line_start;
    line_start.x = -5.0;
    line_start.y = -5.0;

    geometry_msgs::Point line_end;
    line_end.x = 5.0;
    line_end.y = 5.0;

    map_goals.push_back(boost::make_shared<grid_map_planner_goal_types::LineSegmentGoal>(
                                            line_start,
                                            line_end,
                                            0.0,
                                            gp_.getPlanningMap()));

    geometry_msgs::Pose goal_pose;
    goal_pose.position.x = -2.0;
    goal_pose.position.y = -0.4;
    goal_pose.orientation.w = 1.0;
    map_goals.push_back(boost::make_shared<grid_map_planner_goal_types::PoseGoal>(
                                            goal_pose,
                                            gp_.getPlanningMap()));

    int reached_idx;
    gp_.makePlan(msg->pose.pose, map_goals, path.poses, reached_idx);

    path_pub_.publish(path);

    grid_map_msgs::GridMap grid_map_out;
    grid_map::GridMapRosConverter::toMessage(gp_.getPlanningMap(), grid_map_out);
    std::cout << "Planning multi goal path took " << (ros::WallTime::now() - start_time).toSec() * 1000 << " ms\n";

    //grid_map::GridMapRosConverter::toMessage(map, grid_map_out);
    map_pub_.publish(grid_map_out);
  }

  void map_cb(const nav_msgs::OccupancyGridConstPtr& grid_map_msg)
  {
    ROS_INFO("Received map");
    grid_map::GridMap map;
    grid_map::GridMapRosConverter::fromOccupancyGrid(*grid_map_msg, std::string("occupancy"), map);
    gp_.setMap(map);

    grid_map_msgs::GridMap grid_map_out;
    grid_map::GridMapRosConverter::toMessage(gp_.getPlanningMap(), grid_map_out);

    std::cout << "layers: " << gp_.getPlanningMap().getLayers().size() << "\n";
    //grid_map::GridMapRosConverter::toMessage(map, grid_map_out);
    map_pub_.publish(grid_map_out);
    ROS_INFO("Map callback completed");
  }

  void plan_path_to_goal()
  {
    ROS_INFO("Plan path to goal");

    ros::WallTime start_time = ros::WallTime::now();
    //std::vector<geometry_msgs::PoseStamped> path;
    nav_msgs::Path path;
    path.header.stamp = ros::Time::now();
    path.header.frame_id = "map";
    if (!gp_.makePlan(start_pose, goal_pose ,path.poses)){
      ROS_WARN("makePlan failed");
    }

    std::cout << "Generating plan took " << (ros::WallTime::now() - start_time).toSec() * 1000 << " ms\n";

    path_pub_.publish(path);

    start_time = ros::WallTime::now();
    grid_map_msgs::GridMap grid_map_out;
    grid_map::GridMapRosConverter::toMessage(gp_.getPlanningMap(), grid_map_out);

    //grid_map::GridMapRosConverter::toMessage(map, grid_map_out);
    map_pub_.publish(grid_map_out);
    std::cout << "Publishing map took " << (ros::WallTime::now() - start_time).toSec() * 1000 << " ms\n";
  }

protected:
  grid_map_planner::GridMapPlanner gp_;

  ros::Subscriber map_sub_;

  ros::Publisher map_pub_;
  ros::Publisher path_pub_;

  ros::Subscriber goal_pose_sub_;
  ros::Subscriber search_pose_sub_;
  ros::Subscriber pose_with_cov_sub_;
  ros::Subscriber exploration_start_pose_sub_;
  ros::Subscriber multi_goal_start_pose_sub_;

  geometry_msgs::Pose start_pose;
  geometry_msgs::Pose goal_pose;

};

int main(int argc, char **argv) {
  ros::init(argc, argv, ROS_PACKAGE_NAME);

  /*
  // Quickly testing storage order :)
  Eigen::Matrix<float, 3, 3> matrix ;
  matrix << 0, 1, 2, 3, 4 ,5 ,6 ,7 , 8;
  std::cout << "\n" << matrix << "\n";
  std::cout << "0,0: " << matrix(0,0) << " 0,1: " << matrix(0,1) << " 1,0: " << matrix(1,0) << "\n";
  std::cout << "In memory:" << std::endl;
  for (int i = 0; i < matrix.size(); i++)
    std::cout << *(matrix.data() + i) << "  ";
  std::cout << std::endl << std::endl;
  */

  TestGridMapPlanner ep;

  ros::spin();

  return 0;
}
<commit_msg>test changed to provoke a crash<commit_after>//=================================================================================================
// Copyright (c) 2016, Stefan Kohlbrecher, TU Darmstadt
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Simulation, Systems Optimization and Robotics
//       group, TU Darmstadt nor the names of its contributors may be used to
//       endorse or promote products derived from this software without
//       specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//=================================================================================================

#include <ros/ros.h>
#include <grid_map_planner_lib/grid_map_planner.h>

#include <nav_msgs/OccupancyGrid.h>
#include <geometry_msgs/PoseWithCovarianceStamped.h>
#include <grid_map_ros/GridMapRosConverter.hpp>

#include <nav_msgs/Path.h>

class TestGridMapPlanner
{
public:
  TestGridMapPlanner()
  {
    ros::NodeHandle nh;

    map_sub_ = nh.subscribe("/map",10,&TestGridMapPlanner::map_cb,this);

    map_pub_ = nh.advertise<grid_map_msgs::GridMap>("/grid_map", 2, true);
    path_pub_ = nh.advertise<nav_msgs::Path>("/path", 2, true);

    goal_pose_sub_ = nh.subscribe("/goal", 2, &TestGridMapPlanner::goalPoseCallback, this);
    search_pose_sub_ = nh.subscribe("/search_pose", 2, &TestGridMapPlanner::searchPoseCallback, this);
    pose_with_cov_sub_ = nh.subscribe("/initialpose", 2, &TestGridMapPlanner::poseWithCovCallback, this);
    exploration_start_pose_sub_ = nh.subscribe("/explore_initialpose", 2, &TestGridMapPlanner::explorePoseCallback, this);
    multi_goal_start_pose_sub_ = nh.subscribe("/multi_goal_initialpose", 2, &TestGridMapPlanner::multiGoalPoseCallback, this);

  }

  void goalPoseCallback(const geometry_msgs::PoseStamped::ConstPtr& msg)
  {
    ROS_INFO("Goal pose callback");

    goal_pose = msg->pose;
    this->plan_path_to_goal();
  }

  void searchPoseCallback(const geometry_msgs::PoseStamped::ConstPtr& msg)
  {
    ROS_INFO("Search pose callback");
  }

  void poseWithCovCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg)
  {
    ROS_INFO("Start pose callback");
    start_pose = msg->pose.pose;
    this->plan_path_to_goal();
  }

  void explorePoseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg)
  {
    ROS_INFO("Explore pose callback");

    ros::WallTime start_time = ros::WallTime::now();

    nav_msgs::Path path;
    path.header.stamp = ros::Time::now();
    path.header.frame_id = "map";

    gp_.makeExplorationPlan(msg->pose.pose, path.poses);

    path_pub_.publish(path);

    grid_map_msgs::GridMap grid_map_out;
    grid_map::GridMapRosConverter::toMessage(gp_.getPlanningMap(), grid_map_out);
    std::cout << "Planning exploration took " << (ros::WallTime::now() - start_time).toSec() * 1000 << " ms\n";

    //grid_map::GridMapRosConverter::toMessage(map, grid_map_out);
    map_pub_.publish(grid_map_out);
  }

  void multiGoalPoseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg)
  {
    ROS_INFO("Multi goal pose callback");

    ros::WallTime start_time = ros::WallTime::now();

    nav_msgs::Path path;
    path.header.stamp = ros::Time::now();
    path.header.frame_id = "map";

    std::vector<boost::shared_ptr<grid_map_planner_goal_types::MapGoalBase> > map_goals;

    geometry_msgs::Point line_start;
    line_start.x = 20;
    line_start.y = -0.5;

    geometry_msgs::Point line_end;
    line_end.x = 20;
    line_end.y = -2;

    map_goals.push_back(boost::make_shared<grid_map_planner_goal_types::LineSegmentGoal>(
                                            line_start,
                                            line_end,
                                            0.0,
                                            gp_.getPlanningMap()));

    geometry_msgs::Pose goal_pose;
    goal_pose.position.x = 12.51;
    goal_pose.position.y = -6.1;
    goal_pose.orientation.w = 1.0;
    map_goals.push_back(boost::make_shared<grid_map_planner_goal_types::PoseGoal>(
                                            goal_pose,
                                            gp_.getPlanningMap()));

    int reached_idx;
    gp_.makePlan(msg->pose.pose, map_goals, path.poses, reached_idx);

    path_pub_.publish(path);

    grid_map_msgs::GridMap grid_map_out;
    grid_map::GridMapRosConverter::toMessage(gp_.getPlanningMap(), grid_map_out);
    std::cout << "Planning multi goal path took " << (ros::WallTime::now() - start_time).toSec() * 1000 << " ms\n";

    //grid_map::GridMapRosConverter::toMessage(map, grid_map_out);
    map_pub_.publish(grid_map_out);
  }

  void map_cb(const nav_msgs::OccupancyGridConstPtr& grid_map_msg)
  {
    ROS_INFO("Received map");
    grid_map::GridMap map;
    grid_map::GridMapRosConverter::fromOccupancyGrid(*grid_map_msg, std::string("occupancy"), map);
    gp_.setMap(map);

    grid_map_msgs::GridMap grid_map_out;
    grid_map::GridMapRosConverter::toMessage(gp_.getPlanningMap(), grid_map_out);

    std::cout << "layers: " << gp_.getPlanningMap().getLayers().size() << "\n";
    //grid_map::GridMapRosConverter::toMessage(map, grid_map_out);
    map_pub_.publish(grid_map_out);
    ROS_INFO("Map callback completed");
  }

  void plan_path_to_goal()
  {
    ROS_INFO("Plan path to goal");

    ros::WallTime start_time = ros::WallTime::now();
    //std::vector<geometry_msgs::PoseStamped> path;
    nav_msgs::Path path;
    path.header.stamp = ros::Time::now();
    path.header.frame_id = "map";
    if (!gp_.makePlan(start_pose, goal_pose ,path.poses)){
      ROS_WARN("makePlan failed");
    }

    std::cout << "Generating plan took " << (ros::WallTime::now() - start_time).toSec() * 1000 << " ms\n";

    path_pub_.publish(path);

    start_time = ros::WallTime::now();
    grid_map_msgs::GridMap grid_map_out;
    grid_map::GridMapRosConverter::toMessage(gp_.getPlanningMap(), grid_map_out);

    //grid_map::GridMapRosConverter::toMessage(map, grid_map_out);
    map_pub_.publish(grid_map_out);
    std::cout << "Publishing map took " << (ros::WallTime::now() - start_time).toSec() * 1000 << " ms\n";
  }

protected:
  grid_map_planner::GridMapPlanner gp_;

  ros::Subscriber map_sub_;

  ros::Publisher map_pub_;
  ros::Publisher path_pub_;

  ros::Subscriber goal_pose_sub_;
  ros::Subscriber search_pose_sub_;
  ros::Subscriber pose_with_cov_sub_;
  ros::Subscriber exploration_start_pose_sub_;
  ros::Subscriber multi_goal_start_pose_sub_;

  geometry_msgs::Pose start_pose;
  geometry_msgs::Pose goal_pose;

};

int main(int argc, char **argv) {
  ros::init(argc, argv, ROS_PACKAGE_NAME);

  /*
  // Quickly testing storage order :)
  Eigen::Matrix<float, 3, 3> matrix ;
  matrix << 0, 1, 2, 3, 4 ,5 ,6 ,7 , 8;
  std::cout << "\n" << matrix << "\n";
  std::cout << "0,0: " << matrix(0,0) << " 0,1: " << matrix(0,1) << " 1,0: " << matrix(1,0) << "\n";
  std::cout << "In memory:" << std::endl;
  for (int i = 0; i < matrix.size(); i++)
    std::cout << *(matrix.data() + i) << "  ";
  std::cout << std::endl << std::endl;
  */

  TestGridMapPlanner ep;

  ros::spin();

  return 0;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
// FILE:          VirtualShutter.cpp
// PROJECT:       100X micro-manager extensions
// SUBSYSTEM:     DeviceAdapters : TwoPhoton
//-----------------------------------------------------------------------------
// DESCRIPTION:   Dual shutter for two D/A channels
//
// AUTHOR:        Nenad Amodaj, February 2010
//
// COPYRIGHT:     100X Imaging Inc, 2010
//

#include "TwoPhoton.h"
#include <sstream>
#include "DeviceUtils.h"

using namespace std;

const char* g_VShutterDeviceName = "VDualShuuter";
const char* g_DemoLaserDeviceName = "DemoLaser";

const char* g_PropertyOnOff = "OnOff";
const char* g_PropertyPower = "Power";
const char* g_PropertyWL = "Wavelength";
const char* g_PropertyShutter = "Shutter";
const char* g_PropertyWarmedup = "Warmedup";

const char* g_ON = "ON";
const char* g_OFF = "OFF";

const char* g_cmd_warmedup = "READ:PCTWARMEDUP?";
const char* g_cmd_power = "READ:POWER?";
const char* g_cmd_wl_query = "READ:WAVELENGTH?";
const char* g_cmd_wl = "WAVELENGTH";
const char* g_cmd_wl_min = "WAVELENGTH:MIN?";
const char* g_cmd_wl_max = "WAVELENGTH:MAX?";
const char* g_cmd_ON = "ON";
const char* g_cmd_OFF = "OFF";
const char* g_cmd_shutter_query = "SHUTTER?";
const char* g_cmd_shutter = "SHUTTER";

///////////////////////////////////////////////////////////////////////////////
// MaiTai control implementation
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
 * Constructor.
 */
MaiTai::MaiTai() :
   initialized_(false)
{
   // call the base class method to set-up default error codes/messages
   InitializeDefaultErrorMessages();

   // set custom error messages
   SetErrorText(ERR_NOT_WARMED_UP, "Laser not warmed up yet.");

   // Port
   CPropertyAction* pAct = new CPropertyAction (this, &MaiTai::OnComPort);
   CreateProperty(MM::g_Keyword_Port, "Undefined", MM::String, false, pAct, true);
}

MaiTai::~MaiTai()
{
   Shutdown();
}

/**
 * Obtains device name.
 */
void MaiTai::GetName(char* name) const
{
   CDeviceUtils::CopyLimitedString(name, g_MaiTaiDeviceName);
}

/**
 * Intializes the hardware.
 */
int MaiTai::Initialize()
{
   if (initialized_)
      return DEVICE_OK;

   // set property list
   // -----------------

   // Name
   int ret = CreateProperty(MM::g_Keyword_Name, g_MaiTaiDeviceName, MM::String, true);
   if (DEVICE_OK != ret)
      return ret;

   // Description
   ret = CreateProperty(MM::g_Keyword_Description, "MaiTai lser control", MM::String, true);
   if (DEVICE_OK != ret)
      return ret;

   // OnOff
   CPropertyAction *pAct = new CPropertyAction (this, &MaiTai::OnOnOff);
   ret = CreateProperty(g_PropertyOnOff, g_OFF, MM::String, false, pAct);
   assert(ret == DEVICE_OK);

   vector<string> onOffValues;
   onOffValues.push_back(g_OFF);
   onOffValues.push_back(g_ON);
   ret = SetAllowedValues(g_PropertyOnOff, onOffValues);
   if (ret != DEVICE_OK)
      return ret;

   // Shutter
   pAct = new CPropertyAction (this, &MaiTai::OnShutter);
   ret = CreateProperty(g_PropertyShutter, "0", MM::Integer, false, pAct);
   assert(ret == DEVICE_OK);

   vector<string> shutterValues;
   shutterValues.push_back("0");
   shutterValues.push_back("1");
   ret = SetAllowedValues(g_PropertyShutter, shutterValues);
   if (ret != DEVICE_OK)
      return ret;

   // Wavelength
   pAct = new CPropertyAction (this, &MaiTai::OnWavelength);
   ret = CreateProperty(g_PropertyWL, "0", MM::Integer, false, pAct);
   assert(ret == DEVICE_OK);

   SetPropertyLimits(g_PropertyWL, 400, 1000);

   // Power
   pAct = new CPropertyAction (this, &MaiTai::OnPower);
   ret = CreateProperty(g_PropertyPower, "0", MM::Float, true, pAct);
   assert(ret == DEVICE_OK);

   // Power
   pAct = new CPropertyAction (this, &MaiTai::OnWarmedup);
   ret = CreateProperty(g_PropertyWarmedup, "0", MM::String, true, pAct);
   assert(ret == DEVICE_OK);

   // check warmed-up status
   ret = SendSerialCommand(port_.c_str(), g_cmd_warmedup, "\n");
   if (ret != DEVICE_OK)
      return ret;

   string answer;
   ret = GetSerialAnswer(port_.c_str(), "\n", answer);
   if (ret != DEVICE_OK)
      return false;
/*
   pAct = new CPropertyAction (this, &MaiTai::OnWarmedup);
   ret = CreateProperty(g_PropertyWarmedup, "0%", MM::String, true, pAct);
   assert(ret == DEVICE_OK);
*/

   // determine wl limits
   ret = SendSerialCommand(port_.c_str(), g_cmd_wl_min, "\n");
   if (ret != DEVICE_OK)
      return ret;

   string ansWlMin;
   ret = GetSerialAnswer(port_.c_str(), "\n", ansWlMin);
   if (ret != DEVICE_OK)
      return false;

   ret = SendSerialCommand(port_.c_str(), g_cmd_wl_max, "\n");
   if (ret != DEVICE_OK)
      return ret;

   string ansWlMax;
   ret = GetSerialAnswer(port_.c_str(), "\n", ansWlMax);
   if (ret != DEVICE_OK)
      return false;

   int wlMin = atoi(ansWlMin.c_str());
   int wlMax = atoi(ansWlMax.c_str());
   SetPropertyLimits(g_PropertyWL, wlMin, wlMax);

   // synchronize all properties
   // --------------------------
   ret = UpdateStatus();
   if (ret != DEVICE_OK)
      return ret;

   initialized_ = true;
   return DEVICE_OK;
}

/**
 * Shuts down (unloads) the device.
 */
int MaiTai::Shutdown()
{
   if (initialized_)
      SetProperty(g_PropertyOnOff, g_OFF);

   initialized_ = false;

   return DEVICE_OK;
}

int MaiTai::OnPower(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::AfterSet)
   {
   }
   else if (eAct == MM::BeforeGet)
   {
      // query power
      int ret = SendSerialCommand(port_.c_str(), g_cmd_power, "\n");
      if (ret != DEVICE_OK)
         return ret;

      string answer;
      ret = GetSerialAnswer(port_.c_str(), "\n", answer);
      if (ret != DEVICE_OK)
         return false;

      pProp->Set(answer.c_str());
   }

   return DEVICE_OK;
}

int MaiTai::OnWarmedup(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::AfterSet)
   {
   }
   else if (eAct == MM::BeforeGet)
   {
      // query power
      int ret = SendSerialCommand(port_.c_str(), g_cmd_warmedup, "\n");
      if (ret != DEVICE_OK)
         return ret;

      string answer;
      ret = GetSerialAnswer(port_.c_str(), "\n", answer);
      if (ret != DEVICE_OK)
         return false;

      pProp->Set(answer.c_str());
   }

   return DEVICE_OK;
}
int MaiTai::OnWavelength(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::AfterSet)
   {
      string wl;
      pProp->Get(wl);

      // set wavelength
      ostringstream cmd;
      cmd << g_cmd_wl << " " << wl;
      int ret = SendSerialCommand(port_.c_str(), cmd.str().c_str(), "\n");
      if (ret != DEVICE_OK)
         return ret;

   }
   else if (eAct == MM::BeforeGet)
   {
      // query wavelength
      int ret = SendSerialCommand(port_.c_str(), g_cmd_wl_query, "\n");
      if (ret != DEVICE_OK)
         return ret;

      string answer;
      ret = GetSerialAnswer(port_.c_str(), "\n", answer);
      if (ret != DEVICE_OK)
         return false;

      pProp->Set(answer.c_str());
   }
   return DEVICE_OK;
}

int MaiTai::OnShutter(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::AfterSet)
   {
      long s;
      pProp->Get(s);

      // set shutter
      ostringstream cmd;
      cmd << g_cmd_shutter << " " << s;
      int ret = SendSerialCommand(port_.c_str(), cmd.str().c_str(), "\n");
      if (ret != DEVICE_OK)
         return ret;

   }
   else if (eAct == MM::BeforeGet)
   {
      // query wavelength
      int ret = SendSerialCommand(port_.c_str(), g_cmd_shutter_query, "\n");
      if (ret != DEVICE_OK)
         return ret;

      string answer;
      ret = GetSerialAnswer(port_.c_str(), "\n", answer);
      if (ret != DEVICE_OK)
         return false;

      pProp->Set(answer.c_str());
   }
   return DEVICE_OK;
}

int MaiTai::OnOnOff(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::AfterSet)
   {
      string val;
      pProp->Get(val);
      if (val.compare(g_ON) == 0)
      {
         // check the warmup status
         int ret = SendSerialCommand(port_.c_str(), g_cmd_warmedup, "\n");
         if (ret != DEVICE_OK)
            return ret;

         string answer;
         ret = GetSerialAnswer(port_.c_str(), "\n", answer);
         if (ret != DEVICE_OK)
            return false;

         // send ON command
         ret = SendSerialCommand(port_.c_str(), g_cmd_ON, "\n");
         if (ret != DEVICE_OK)
            return ret;
      }
      else
      {
          // send OFF command
         int ret = SendSerialCommand(port_.c_str(), g_cmd_OFF, "\n");
         if (ret != DEVICE_OK)
            return ret;
     }
   }
   else if (eAct == MM::BeforeGet)
   {
   }
   return DEVICE_OK;
}

int MaiTai::OnComPort(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(port_.c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      if (initialized_)
      {
         // revert
         pProp->Set(port_.c_str());
         return ERR_PORT_CHANGE_FORBIDDEN;
      }

      pProp->Get(port_);
   }

   return DEVICE_OK;
}

///////////////////////////////////////////////////////////////////////////////
// DemoLaser control implementation
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
 * Constructor.
 */
DemoLaser::DemoLaser() :
   initialized_(false)
{
   // call the base class method to set-up default error codes/messages
   InitializeDefaultErrorMessages();

}

DemoLaser::~DemoLaser()
{
   Shutdown();
}

/**
 * Obtains device name.
 */
void DemoLaser::GetName(char* name) const
{
   CDeviceUtils::CopyLimitedString(name, g_DemoLaserDeviceName);
}

/**
 * Intializes the hardware.
 */
int DemoLaser::Initialize()
{
   if (initialized_)
      return DEVICE_OK;

   // set property list
   // -----------------

   // Name
   int ret = CreateProperty(MM::g_Keyword_Name, g_MaiTaiDeviceName, MM::String, true);
   if (DEVICE_OK != ret)
      return ret;

   // Description
   ret = CreateProperty(MM::g_Keyword_Description, "Demo laser control", MM::String, true);
   if (DEVICE_OK != ret)
      return ret;

   // OnOff
   ret = CreateProperty(g_PropertyOnOff, g_OFF, MM::String, false);
   assert(ret == DEVICE_OK);

   vector<string> onOffValues;
   onOffValues.push_back(g_OFF);
   onOffValues.push_back(g_ON);
   ret = SetAllowedValues(g_PropertyOnOff, onOffValues);
   if (ret != DEVICE_OK)
      return ret;

   // Wavelength
   ret = CreateProperty(g_PropertyWL, "0", MM::Integer, false);
   assert(ret == DEVICE_OK);

   SetPropertyLimits(g_PropertyWL, 400, 1000);

   // Power
   ret = CreateProperty(g_PropertyPower, "0", MM::Integer, true);
   assert(ret == DEVICE_OK);

   // synchronize all properties
   // --------------------------
   ret = UpdateStatus();
   if (ret != DEVICE_OK)
      return ret;

   initialized_ = true;
   return DEVICE_OK;
}

/**
 * Shuts down (unloads) the device.
 */
int DemoLaser::Shutdown()
{
   initialized_ = false;

   return DEVICE_OK;
}

<commit_msg>deleted old virtual shutter class<commit_after><|endoftext|>


<commit_before>/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma once
#include <eosiolib/print.h>
#include <eosiolib/types.hpp>
#include <eosiolib/fixed_key.hpp>
#include <utility>

namespace eosio {

   static_assert( sizeof(long) == sizeof(int), "unexpected size difference" );

   /**
    *  Prints string
    *  @brief Prints string
    *  @param ptr - a null terminated string
    */
   inline void print( const char* ptr ) {
      prints(ptr);
   }

   /**
    * Prints signed integer
    * @brief Prints signed integer as a 64 bit signed integer
    * @param num to be printed
    */
   inline void print( int num ) {
      printi(num);
   }

   /**
    * Prints 32 bit signed integer
    * @brief Prints 32 bit signed integer as a 64 bit signed integer
    * @param num to be printed
    */
   inline void print( int32_t num ) {
      printi(num);
   }

   /**
    * Prints 64 bit signed integer
    * @brief Prints 64 bit signed integer as a 64 bit signed integer
    * @param num to be printed
    */
   inline void print( int64_t num ) {
      printi(num);
   }

   /**
    * Prints unsigned integer
    * @brief Prints unsigned integer as a 64 bit unsigned integer
    * @param num to be printed
    */
   inline void print( unsigned int num ) {
      printui(num);
   }

   /**
    * Prints 32 bit unsigned integer
    * @brief Prints 32 bit unsigned integer as a 64 bit unsigned integer
    * @param num to be printed
    */
   inline void print( uint32_t num ) {
      printui(num);
   }

   /**
    * Prints 64 bit unsigned integer
    * @brief Prints 64 bit unsigned integer as a 64 bit unsigned integer
    * @param num to be printed
    */
   inline void print( uint64_t num ) {
      printui(num);
   }

   /**
    * Prints 128 bit signed integer
    * @brief Prints 128 bit signed integer
    * @param num to be printed
    */
   inline void print( int128_t num ) {
      printi128(&num);
   }

   /**
    * Prints 128 bit unsigned integer
    * @brief Prints 128 bit unsigned integer
    * @param num to be printed
    */
   inline void print( uint128_t num ) {
      printui128(&num);
   }

   /**
    * Prints single-precision floating point number
    * @brief Prints single-precision floating point number (i.e. float)
    * @param num to be printed
    */
   inline void print( float num ) { printsf( num ); }

   /**
    * Prints double-precision floating point number
    * @brief Prints double-precision floating point number (i.e. double)
    * @param num to be printed
    */
   inline void print( double num ) { printdf( num ); }

   /**
    * Prints quadruple-precision floating point number
    * @brief Prints quadruple-precision floating point number (i.e. long double)
    * @param num to be printed
    */
   inline void print( long double num ) { printqf( &num ); }

   /**
    * Prints fixed_key as a hexidecimal string
    * @brief Prints fixed_key as a hexidecimal string
    * @param val to be printed
    */
   template<size_t Size>
   inline void print( const fixed_key<Size>& val ) {
      auto arr = val.extract_as_byte_array();
      prints("0x");
      printhex(static_cast<const void*>(arr.data()), arr.size());
   }

   template<size_t Size>
   inline void print( fixed_key<Size>& val ) {
      print(static_cast<const fixed_key<Size>&>(val));
   }

   /**
    * Prints a 64 bit names as base32 encoded string
    * @brief Prints a 64 bit names as base32 encoded string
    * @param name 64 bit name to be printed
    */
   inline void print( name name ) {
      printn(name.value);
   }

   inline void print( bool val ) {
      prints(val?"true":"false");
   }

   template<typename T>
   inline void print( T&& t ) {
      t.print();
   }

   inline void print_f( const char* s ) {
      prints(s);
   }

   template <typename Arg, typename... Args>
   inline void print_f( const char* s, Arg val, Args... rest ) {
      while ( *s != '\0' ) {
         if ( *s == '%' ) {
            print( val );
            print_f( s+1, rest... );
            return;
         }
         prints_l( s, 1 );
         s++;
      }
   }

   /**
    *  @defgroup consoleCppapi Console C++ API
    *  @ingroup consoleapi
    *  @brief C++ wrapper for Console C API
    *
    *  This API uses C++ variadic templates and type detection to
    *  make it easy to print any native type. You can even overload
    *  the `print()` method for your own custom types.
    *
    *  **Example:**
    *  ```
    *     print( "hello world, this is a number: ", 5 );
    *  ```
    *
    *  @section override Overriding Print for your Types
    *
    *  There are two ways to overload print:
    *  1. implement void print( const T& )
    *  2. implement T::print()const
    *
    *  @{
    */

    /**
     *  Print out value / list of values (except double)
     *  @brief Print out value  / list of values
     *  @param a    Value to be printed
     *  @param args Other values to be printed
     *
     *  Example:
     *  @code
     *  const char *s = "Hello World!";
     *  uint64_t unsigned_64_bit_int = 1e+18;
     *  uint128_t unsigned_128_bit_int (87654323456);
     *  uint64_t string_as_unsigned_64_bit = N(abcde);
     *  print(s , unsigned_64_bit_int, unsigned_128_bit_int, string_as_unsigned_64_bit);
     *  // Ouput: Hello World!100000000000000000087654323456abcde
     *  @endcode
     */
   template<typename Arg, typename... Args>
   void print( Arg&& a, Args&&... args ) {
      print(std::forward<Arg>(a));
      print(std::forward<Args>(args)...);
   }

   /**
    * Simulate C++ style streams
    */
   class iostream {};

   /**
    *  Overload c++ iostream
    *  @brief Overload c++ iostream
    *  @param out  Output strem
    *  @param v    Value to be printed
    *
    *  Example:
    *  @code
    *  const char *s = "Hello World!";
    *  uint64_t unsigned_64_bit_int = 1e+18;
    *  uint128_t unsigned_128_bit_int (87654323456);
    *  uint64_t string_as_unsigned_64_bit = N(abcde);
    *  std::out << s << " " << unsigned_64_bit_int << " "  << unsigned_128_bit_int << " " << string_as_unsigned_64_bit;
    *  // Output: Hello World! 1000000000000000000 87654323456 abcde
    *  @endcode
    */
   template<typename T>
   inline iostream& operator<<( iostream& out, const T& v ) {
      print( v );
      return out;
   }

   static iostream cout;

   /// @} consoleCppapi

}
<commit_msg>Add impl for std::string printing, #2984<commit_after>/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma once
#include <eosiolib/print.h>
#include <eosiolib/types.hpp>
#include <eosiolib/fixed_key.hpp>
#include <utility>
#include <string>

namespace eosio {

   static_assert( sizeof(long) == sizeof(int), "unexpected size difference" );

   /**
    *  Prints string
    *  @brief Prints string
    *  @param ptr - a null terminated string
    */
   inline void print( const char* ptr ) {
      prints(ptr);
   }

   inline void print( const std::string& s) {
      prints(s.c_str());
   }

   /**
    * Prints signed integer
    * @brief Prints signed integer as a 64 bit signed integer
    * @param num to be printed
    */
   inline void print( int num ) {
      printi(num);
   }

   /**
    * Prints 32 bit signed integer
    * @brief Prints 32 bit signed integer as a 64 bit signed integer
    * @param num to be printed
    */
   inline void print( int32_t num ) {
      printi(num);
   }

   /**
    * Prints 64 bit signed integer
    * @brief Prints 64 bit signed integer as a 64 bit signed integer
    * @param num to be printed
    */
   inline void print( int64_t num ) {
      printi(num);
   }

   /**
    * Prints unsigned integer
    * @brief Prints unsigned integer as a 64 bit unsigned integer
    * @param num to be printed
    */
   inline void print( unsigned int num ) {
      printui(num);
   }

   /**
    * Prints 32 bit unsigned integer
    * @brief Prints 32 bit unsigned integer as a 64 bit unsigned integer
    * @param num to be printed
    */
   inline void print( uint32_t num ) {
      printui(num);
   }

   /**
    * Prints 64 bit unsigned integer
    * @brief Prints 64 bit unsigned integer as a 64 bit unsigned integer
    * @param num to be printed
    */
   inline void print( uint64_t num ) {
      printui(num);
   }

   /**
    * Prints 128 bit signed integer
    * @brief Prints 128 bit signed integer
    * @param num to be printed
    */
   inline void print( int128_t num ) {
      printi128(&num);
   }

   /**
    * Prints 128 bit unsigned integer
    * @brief Prints 128 bit unsigned integer
    * @param num to be printed
    */
   inline void print( uint128_t num ) {
      printui128(&num);
   }

   /**
    * Prints single-precision floating point number
    * @brief Prints single-precision floating point number (i.e. float)
    * @param num to be printed
    */
   inline void print( float num ) { printsf( num ); }

   /**
    * Prints double-precision floating point number
    * @brief Prints double-precision floating point number (i.e. double)
    * @param num to be printed
    */
   inline void print( double num ) { printdf( num ); }

   /**
    * Prints quadruple-precision floating point number
    * @brief Prints quadruple-precision floating point number (i.e. long double)
    * @param num to be printed
    */
   inline void print( long double num ) { printqf( &num ); }

   /**
    * Prints fixed_key as a hexidecimal string
    * @brief Prints fixed_key as a hexidecimal string
    * @param val to be printed
    */
   template<size_t Size>
   inline void print( const fixed_key<Size>& val ) {
      auto arr = val.extract_as_byte_array();
      prints("0x");
      printhex(static_cast<const void*>(arr.data()), arr.size());
   }

   template<size_t Size>
   inline void print( fixed_key<Size>& val ) {
      print(static_cast<const fixed_key<Size>&>(val));
   }

   /**
    * Prints a 64 bit names as base32 encoded string
    * @brief Prints a 64 bit names as base32 encoded string
    * @param name 64 bit name to be printed
    */
   inline void print( name name ) {
      printn(name.value);
   }

   inline void print( bool val ) {
      prints(val?"true":"false");
   }

   template<typename T>
   inline void print( T&& t ) {
      t.print();
   }

   inline void print_f( const char* s ) {
      prints(s);
   }

   template <typename Arg, typename... Args>
   inline void print_f( const char* s, Arg val, Args... rest ) {
      while ( *s != '\0' ) {
         if ( *s == '%' ) {
            print( val );
            print_f( s+1, rest... );
            return;
         }
         prints_l( s, 1 );
         s++;
      }
   }

   /**
    *  @defgroup consoleCppapi Console C++ API
    *  @ingroup consoleapi
    *  @brief C++ wrapper for Console C API
    *
    *  This API uses C++ variadic templates and type detection to
    *  make it easy to print any native type. You can even overload
    *  the `print()` method for your own custom types.
    *
    *  **Example:**
    *  ```
    *     print( "hello world, this is a number: ", 5 );
    *  ```
    *
    *  @section override Overriding Print for your Types
    *
    *  There are two ways to overload print:
    *  1. implement void print( const T& )
    *  2. implement T::print()const
    *
    *  @{
    */

    /**
     *  Print out value / list of values (except double)
     *  @brief Print out value  / list of values
     *  @param a    Value to be printed
     *  @param args Other values to be printed
     *
     *  Example:
     *  @code
     *  const char *s = "Hello World!";
     *  uint64_t unsigned_64_bit_int = 1e+18;
     *  uint128_t unsigned_128_bit_int (87654323456);
     *  uint64_t string_as_unsigned_64_bit = N(abcde);
     *  print(s , unsigned_64_bit_int, unsigned_128_bit_int, string_as_unsigned_64_bit);
     *  // Ouput: Hello World!100000000000000000087654323456abcde
     *  @endcode
     */
   template<typename Arg, typename... Args>
   void print( Arg&& a, Args&&... args ) {
      print(std::forward<Arg>(a));
      print(std::forward<Args>(args)...);
   }

   /**
    * Simulate C++ style streams
    */
   class iostream {};

   /**
    *  Overload c++ iostream
    *  @brief Overload c++ iostream
    *  @param out  Output strem
    *  @param v    Value to be printed
    *
    *  Example:
    *  @code
    *  const char *s = "Hello World!";
    *  uint64_t unsigned_64_bit_int = 1e+18;
    *  uint128_t unsigned_128_bit_int (87654323456);
    *  uint64_t string_as_unsigned_64_bit = N(abcde);
    *  std::out << s << " " << unsigned_64_bit_int << " "  << unsigned_128_bit_int << " " << string_as_unsigned_64_bit;
    *  // Output: Hello World! 1000000000000000000 87654323456 abcde
    *  @endcode
    */
   template<typename T>
   inline iostream& operator<<( iostream& out, const T& v ) {
      print( v );
      return out;
   }

   static iostream cout;

   /// @} consoleCppapi

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: currentcontextchecker.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2006-12-05 15:02:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2006 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_testtools.hxx"

#include "sal/config.h"

#include "currentcontextchecker.hxx"

#include "com/sun/star/uno/Any.hxx"
#include "com/sun/star/uno/Reference.hxx"
#include "com/sun/star/uno/RuntimeException.hpp"
#include "com/sun/star/uno/XCurrentContext.hpp"
#include "cppu/unotype.hxx"
#include "cppuhelper/implbase1.hxx"
#include "osl/diagnose.h"
#include "osl/diagnose.hxx"
#include "rtl/string.h"
#include "rtl/ustring.hxx"
#include "sal/types.h"
#include "test/testtools/bridgetest/XCurrentContextChecker.hpp"
#include "uno/current_context.hxx"

namespace {

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

static char const key[] = "testtools.bridgetest.Key";
static char const value[] = "good";

class CurrentContext:
    public ::osl::DebugBase< CurrentContext >,
    public ::cppu::WeakImplHelper1< css::uno::XCurrentContext >
{
public:
    CurrentContext();

    virtual ~CurrentContext();

    virtual css::uno::Any SAL_CALL getValueByName(::rtl::OUString const & Name)
        throw (css::uno::RuntimeException);

private:
    CurrentContext(CurrentContext &); // not defined
    void operator =(CurrentContext &); // not defined
};

CurrentContext::CurrentContext() {}

CurrentContext::~CurrentContext() {}

css::uno::Any CurrentContext::getValueByName(::rtl::OUString const & Name)
    throw (css::uno::RuntimeException)
{
    return Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(key))
        ? css::uno::makeAny(::rtl::OUString::createFromAscii(value))
        : css::uno::Any();
}

}

testtools::bridgetest::CurrentContextChecker::CurrentContextChecker() {}

testtools::bridgetest::CurrentContextChecker::~CurrentContextChecker() {}

::sal_Bool testtools::bridgetest::CurrentContextChecker::perform(
    css::uno::Reference<
        ::test::testtools::bridgetest::XCurrentContextChecker > const & other,
    ::sal_Int32 setSteps, ::sal_Int32 checkSteps)
    throw (css::uno::RuntimeException)
{
    if (setSteps == 0) {
        css::uno::ContextLayer layer(new CurrentContext);
        return performCheck(other, setSteps, checkSteps);
    } else {
        return performCheck(other, setSteps, checkSteps);
    }
}

bool testtools::bridgetest::CurrentContextChecker::performCheck(
    css::uno::Reference<
        ::test::testtools::bridgetest::XCurrentContextChecker > const & other,
    ::sal_Int32 setSteps, ::sal_Int32 checkSteps)
{
    OSL_ASSERT(other.is() && checkSteps >= 0);
    if (checkSteps == 0) {
        css::uno::Reference< css::uno::XCurrentContext > context(
            css::uno::getCurrentContext());
        if (!context.is()) {
            return false;
        }
        css::uno::Any a(
            context->getValueByName(::rtl::OUString::createFromAscii(key)));
        if (a.getValueType() != ::cppu::UnoType< ::rtl::OUString >::get()) {
            return false;
        }
        ::rtl::OUString s;
        OSL_VERIFY(a >>= s);
        return s.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(value));
    } else {
        return other->perform(
            this, setSteps >= 0 ? setSteps - 1 : -1, checkSteps - 1);
    }
}
<commit_msg>INTEGRATION: CWS changefileheader (1.3.44); FILE MERGED 2008/03/31 07:26:28 rt 1.3.44.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: currentcontextchecker.cxx,v $
 * $Revision: 1.4 $
 *
 * 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.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_testtools.hxx"

#include "sal/config.h"

#include "currentcontextchecker.hxx"

#include "com/sun/star/uno/Any.hxx"
#include "com/sun/star/uno/Reference.hxx"
#include "com/sun/star/uno/RuntimeException.hpp"
#include "com/sun/star/uno/XCurrentContext.hpp"
#include "cppu/unotype.hxx"
#include "cppuhelper/implbase1.hxx"
#include "osl/diagnose.h"
#include "osl/diagnose.hxx"
#include "rtl/string.h"
#include "rtl/ustring.hxx"
#include "sal/types.h"
#include "test/testtools/bridgetest/XCurrentContextChecker.hpp"
#include "uno/current_context.hxx"

namespace {

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

static char const key[] = "testtools.bridgetest.Key";
static char const value[] = "good";

class CurrentContext:
    public ::osl::DebugBase< CurrentContext >,
    public ::cppu::WeakImplHelper1< css::uno::XCurrentContext >
{
public:
    CurrentContext();

    virtual ~CurrentContext();

    virtual css::uno::Any SAL_CALL getValueByName(::rtl::OUString const & Name)
        throw (css::uno::RuntimeException);

private:
    CurrentContext(CurrentContext &); // not defined
    void operator =(CurrentContext &); // not defined
};

CurrentContext::CurrentContext() {}

CurrentContext::~CurrentContext() {}

css::uno::Any CurrentContext::getValueByName(::rtl::OUString const & Name)
    throw (css::uno::RuntimeException)
{
    return Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(key))
        ? css::uno::makeAny(::rtl::OUString::createFromAscii(value))
        : css::uno::Any();
}

}

testtools::bridgetest::CurrentContextChecker::CurrentContextChecker() {}

testtools::bridgetest::CurrentContextChecker::~CurrentContextChecker() {}

::sal_Bool testtools::bridgetest::CurrentContextChecker::perform(
    css::uno::Reference<
        ::test::testtools::bridgetest::XCurrentContextChecker > const & other,
    ::sal_Int32 setSteps, ::sal_Int32 checkSteps)
    throw (css::uno::RuntimeException)
{
    if (setSteps == 0) {
        css::uno::ContextLayer layer(new CurrentContext);
        return performCheck(other, setSteps, checkSteps);
    } else {
        return performCheck(other, setSteps, checkSteps);
    }
}

bool testtools::bridgetest::CurrentContextChecker::performCheck(
    css::uno::Reference<
        ::test::testtools::bridgetest::XCurrentContextChecker > const & other,
    ::sal_Int32 setSteps, ::sal_Int32 checkSteps)
{
    OSL_ASSERT(other.is() && checkSteps >= 0);
    if (checkSteps == 0) {
        css::uno::Reference< css::uno::XCurrentContext > context(
            css::uno::getCurrentContext());
        if (!context.is()) {
            return false;
        }
        css::uno::Any a(
            context->getValueByName(::rtl::OUString::createFromAscii(key)));
        if (a.getValueType() != ::cppu::UnoType< ::rtl::OUString >::get()) {
            return false;
        }
        ::rtl::OUString s;
        OSL_VERIFY(a >>= s);
        return s.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(value));
    } else {
        return other->perform(
            this, setSteps >= 0 ? setSteps - 1 : -1, checkSteps - 1);
    }
}
<|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.

#include "chrome/common/extensions/extension_error_reporter.h"

#include "build/build_config.h"

#if defined(OS_WIN)
#include "app/win_util.h"
#elif defined(OS_MACOSX)
#include "base/scoped_cftyperef.h"
#include "base/sys_string_conversions.h"
#include <CoreFoundation/CFUserNotification.h>
#endif
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"

// No AddRef required when using ExtensionErrorReporter with RunnableMethod.
// This is okay since the ExtensionErrorReporter is a singleton that lives until
// the end of the process.
template <> struct RunnableMethodTraits<ExtensionErrorReporter> {
  static void RetainCallee(ExtensionErrorReporter*) {}
  static void ReleaseCallee(ExtensionErrorReporter*) {}
};

ExtensionErrorReporter* ExtensionErrorReporter::instance_ = NULL;

// static
void ExtensionErrorReporter::Init(bool enable_noisy_errors) {
  if (!instance_) {
    instance_ = new ExtensionErrorReporter(enable_noisy_errors);
  }
}

// static
ExtensionErrorReporter* ExtensionErrorReporter::GetInstance() {
  CHECK(instance_) << "Init() was never called";
  return instance_;
}

ExtensionErrorReporter::ExtensionErrorReporter(bool enable_noisy_errors)
    : ui_loop_(MessageLoop::current()),
      enable_noisy_errors_(enable_noisy_errors) {
}

void ExtensionErrorReporter::ReportError(const std::string& message,
                                         bool be_noisy) {
  // NOTE: There won't be a ui_loop_ in the unit test environment.
  if (ui_loop_ && MessageLoop::current() != ui_loop_) {
    ui_loop_->PostTask(FROM_HERE,
        NewRunnableMethod(this, &ExtensionErrorReporter::ReportError, message,
                          be_noisy));
    return;
  }

  errors_.push_back(message);

  // TODO(aa): Print the error message out somewhere better. I think we are
  // going to need some sort of 'extension inspector'.
  LOG(WARNING) << message;

  if (enable_noisy_errors_ && be_noisy) {
#if defined(OS_WIN)
    win_util::MessageBox(NULL, UTF8ToWide(message), L"Extension error",
        MB_OK | MB_SETFOREGROUND);
#elif defined(OS_MACOSX)
    // There must be a better way to do this, for all platforms.
    scoped_cftyperef<CFStringRef> message_cf(
        base::SysUTF8ToCFStringRef(message));
    CFOptionFlags response;
    CFUserNotificationDisplayAlert(
        0, kCFUserNotificationCautionAlertLevel, NULL, NULL, NULL,
        CFSTR("Extension error"), message_cf,
        NULL, NULL, NULL, &response);
#else
    // TODO(port)
#endif
  }
}

const std::vector<std::string>* ExtensionErrorReporter::GetErrors() {
  return &errors_;
}

void ExtensionErrorReporter::ClearErrors() {
  errors_.clear();
}
<commit_msg>Increase the severity of the warning that is logged on extension load failure. This doesn't fix the bug, but might help with debugging until we have an alert box.<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.

#include "chrome/common/extensions/extension_error_reporter.h"

#include "build/build_config.h"

#if defined(OS_WIN)
#include "app/win_util.h"
#elif defined(OS_MACOSX)
#include "base/scoped_cftyperef.h"
#include "base/sys_string_conversions.h"
#include <CoreFoundation/CFUserNotification.h>
#endif
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"

// No AddRef required when using ExtensionErrorReporter with RunnableMethod.
// This is okay since the ExtensionErrorReporter is a singleton that lives until
// the end of the process.
template <> struct RunnableMethodTraits<ExtensionErrorReporter> {
  static void RetainCallee(ExtensionErrorReporter*) {}
  static void ReleaseCallee(ExtensionErrorReporter*) {}
};

ExtensionErrorReporter* ExtensionErrorReporter::instance_ = NULL;

// static
void ExtensionErrorReporter::Init(bool enable_noisy_errors) {
  if (!instance_) {
    instance_ = new ExtensionErrorReporter(enable_noisy_errors);
  }
}

// static
ExtensionErrorReporter* ExtensionErrorReporter::GetInstance() {
  CHECK(instance_) << "Init() was never called";
  return instance_;
}

ExtensionErrorReporter::ExtensionErrorReporter(bool enable_noisy_errors)
    : ui_loop_(MessageLoop::current()),
      enable_noisy_errors_(enable_noisy_errors) {
}

void ExtensionErrorReporter::ReportError(const std::string& message,
                                         bool be_noisy) {
  // NOTE: There won't be a ui_loop_ in the unit test environment.
  if (ui_loop_ && MessageLoop::current() != ui_loop_) {
    ui_loop_->PostTask(FROM_HERE,
        NewRunnableMethod(this, &ExtensionErrorReporter::ReportError, message,
                          be_noisy));
    return;
  }

  errors_.push_back(message);

  // TODO(aa): Print the error message out somewhere better. I think we are
  // going to need some sort of 'extension inspector'.
  LOG(ERROR) << "Extension error: " << message;

  if (enable_noisy_errors_ && be_noisy) {
#if defined(OS_WIN)
    win_util::MessageBox(NULL, UTF8ToWide(message), L"Extension error",
        MB_OK | MB_SETFOREGROUND);
#elif defined(OS_MACOSX)
    // There must be a better way to do this, for all platforms.
    scoped_cftyperef<CFStringRef> message_cf(
        base::SysUTF8ToCFStringRef(message));
    CFOptionFlags response;
    CFUserNotificationDisplayAlert(
        0, kCFUserNotificationCautionAlertLevel, NULL, NULL, NULL,
        CFSTR("Extension error"), message_cf,
        NULL, NULL, NULL, &response);
#else
    // TODO(port)
#endif
  }
}

const std::vector<std::string>* ExtensionErrorReporter::GetErrors() {
  return &errors_;
}

void ExtensionErrorReporter::ClearErrors() {
  errors_.clear();
}
<|endoftext|>


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

#include <atlbase.h>
#include <atlcom.h>

#include "base/scoped_comptr_win.h"
#include "base/thread.h"
#include "chrome_frame/bho.h"
#include "chrome_frame/urlmon_moniker.h"
#include "chrome_frame/test/test_server.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
#include "chrome_frame/test/urlmon_moniker_tests.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
#include "testing/gmock_mutant.h"

using testing::_;
using testing::CreateFunctor;
using testing::Eq;
using testing::Invoke;
using testing::SetArgumentPointee;
using testing::StrEq;
using testing::Return;
using testing::WithArg;
using testing::WithArgs;

static int kUrlmonMonikerTimeoutSec = 5;

namespace {
const char kTestContent[] = ""
    "<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />"
    "Test HTML content";
}  // end namespace

class UrlmonMonikerTest : public testing::Test {
 protected:
  UrlmonMonikerTest() {
  }
};

TEST_F(UrlmonMonikerTest, MonikerPatch) {
  EXPECT_EQ(true, MonikerPatch::Initialize());
  EXPECT_EQ(true, MonikerPatch::Initialize());  // Should be ok to call twice.
  MonikerPatch::Uninitialize();
}

// Runs an HTTP server on a worker thread that has a message loop.
class RunTestServer : public base::Thread {
 public:
  RunTestServer()
      : base::Thread("TestServer"),
      default_response_("/", kTestContent),
      ready_(::CreateEvent(NULL, TRUE, FALSE, NULL)) {
  }

  bool Start() {
    bool ret = StartWithOptions(Options(MessageLoop::TYPE_UI, 0));
    if (ret) {
      message_loop()->PostTask(FROM_HERE,
          NewRunnableFunction(&RunTestServer::StartServer, this));
      wait_until_ready();
    }
    return ret;
  }

  static void StartServer(RunTestServer* me) {
    me->server_.reset(new test_server::SimpleWebServer(43210));
    me->server_->AddResponse(&me->default_response_);
    ::SetEvent(me->ready_);
  }

  bool wait_until_ready() {
    return ::WaitForSingleObject(ready_, kUrlmonMonikerTimeoutSec * 1000)
           == WAIT_OBJECT_0;
  }

 protected:
  scoped_ptr<test_server::SimpleWebServer> server_;
  test_server::SimpleResponse default_response_;
  ScopedHandle ready_;
};

// Helper class for running tests that rely on the NavigationManager.
class UrlmonMonikerTestManager {
 public:
  explicit UrlmonMonikerTestManager(const wchar_t* test_url) {
    mock_mgr_.RegisterThreadInstance();
    mock_mgr_.set_url(test_url);
    EXPECT_EQ(true, MonikerPatch::Initialize());
  }

  ~UrlmonMonikerTestManager() {
    MonikerPatch::Uninitialize();
    mock_mgr_.UnregisterThreadInstance();
  }

  chrome_frame_test::TimedMsgLoop& loop() {
    return loop_;
  }

  TestNavigationManager& nav_manager() {
    return mock_mgr_;
  }

 protected:
  TestNavigationManager mock_mgr_;
  chrome_frame_test::TimedMsgLoop loop_;
};

// Wraps the MockBindStatusCallbackImpl mock object and allows the user
// to specify expectations on the callback object.
class UrlmonMonikerTestCallback {
 public:
  explicit UrlmonMonikerTestCallback(UrlmonMonikerTestManager* mgr)
      : mgr_(mgr) {
  }

  ~UrlmonMonikerTestCallback() {
  }

  typedef enum GetBindInfoExpectations {
    EXPECT_NO_CALL,
    REQUEST_SYNCHRONOUS,
    REQUEST_ASYNCHRONOUS,
  } GET_BIND_INFO_EXPECTATION;

  // Sets gmock expectations for the IBindStatusCallback mock object.
  void SetCallbackExpectations(GetBindInfoExpectations bind_info_handling,
                               HRESULT data_available_response,
                               bool quit_loop_on_stop) {
    EXPECT_CALL(callback_, OnProgress(_, _, _, _))
        .WillRepeatedly(Return(S_OK));

    if (bind_info_handling == REQUEST_ASYNCHRONOUS) {
      EXPECT_CALL(callback_, GetBindInfo(_, _))
          .WillOnce(DoAll(
              WithArgs<0, 1>(
                  Invoke(&MockBindStatusCallbackImpl::SetAsyncBindInfo)),
              Return(S_OK)));
    } else if (bind_info_handling == REQUEST_SYNCHRONOUS) {
      EXPECT_CALL(callback_, GetBindInfo(_, _))
          .WillOnce(DoAll(
              WithArgs<0, 1>(
                  Invoke(&MockBindStatusCallbackImpl::SetSyncBindInfo)),
              Return(S_OK)));
    } else {
      DCHECK(bind_info_handling == EXPECT_NO_CALL);
    }

    EXPECT_CALL(callback_, OnStartBinding(_, _))
        .WillOnce(Return(S_OK));

    EXPECT_CALL(callback_, OnDataAvailable(_, _, _, _))
        .WillRepeatedly(Return(data_available_response));

    if (quit_loop_on_stop) {
      // When expecting asynchronous
      EXPECT_CALL(callback_, OnStopBinding(data_available_response, _))
          .WillOnce(DoAll(QUIT_LOOP(mgr_->loop()), Return(S_OK)));
    } else {
      EXPECT_CALL(callback_, OnStopBinding(data_available_response, _))
          .WillOnce(Return(S_OK));
    }
  }

  HRESULT CreateUrlMonikerAndBindToStorage(const wchar_t* url,
                                           IBindCtx** bind_ctx) {
    ScopedComPtr<IMoniker> moniker;
    HRESULT hr = CreateURLMoniker(NULL, url, moniker.Receive());
    EXPECT_TRUE(moniker != NULL);
    if (moniker) {
      ScopedComPtr<IBindCtx> context;
      ::CreateAsyncBindCtx(0, callback(), NULL, context.Receive());
      DCHECK(context);
      ScopedComPtr<IStream> stream;
      hr = moniker->BindToStorage(context, NULL, IID_IStream,
          reinterpret_cast<void**>(stream.Receive()));
      if (SUCCEEDED(hr) && bind_ctx)
        *bind_ctx = context.Detach();
    }
    return hr;
  }

  IBindStatusCallback* callback() {
    return &callback_;
  }

 protected:
  CComObjectStackEx<MockBindStatusCallbackImpl> callback_;
  UrlmonMonikerTestManager* mgr_;
};

// Tests synchronously binding to a moniker and downloading the target.
TEST_F(UrlmonMonikerTest, BindToStorageSynchronous) {
  const wchar_t test_url[] = L"http://localhost:43210/";
  UrlmonMonikerTestManager test(test_url);
  UrlmonMonikerTestCallback callback(&test);

  RunTestServer server_thread;
  EXPECT_TRUE(server_thread.Start());

  callback.SetCallbackExpectations(
      UrlmonMonikerTestCallback::REQUEST_SYNCHRONOUS, S_OK, false);

  ScopedComPtr<IBindCtx> bind_ctx;
  HRESULT hr = callback.CreateUrlMonikerAndBindToStorage(test_url,
                                                         bind_ctx.Receive());
  // The download should have happened synchronously, so we don't expect
  // MK_S_ASYNCHRONOUS or any errors.
  EXPECT_EQ(S_OK, hr);

  IBindCtx* release = bind_ctx.Detach();
  EXPECT_EQ(0, release->Release());

  server_thread.Stop();

  EXPECT_FALSE(test.nav_manager().HasRequestData());
}

// Tests asynchronously binding to a moniker and downloading the target.
TEST_F(UrlmonMonikerTest, BindToStorageAsynchronous) {
  const wchar_t test_url[] = L"http://localhost:43210/";
  UrlmonMonikerTestManager test(test_url);
  UrlmonMonikerTestCallback callback(&test);

  test_server::SimpleWebServer server(43210);
  test_server::SimpleResponse default_response("/", kTestContent);
  server.AddResponse(&default_response);

  callback.SetCallbackExpectations(
      UrlmonMonikerTestCallback::REQUEST_ASYNCHRONOUS, S_OK, true);

  ScopedComPtr<IBindCtx> bind_ctx;
  HRESULT hr = callback.CreateUrlMonikerAndBindToStorage(test_url,
                                                         bind_ctx.Receive());
  EXPECT_EQ(MK_S_ASYNCHRONOUS, hr);
  test.loop().RunFor(kUrlmonMonikerTimeoutSec);

  IBindCtx* release = bind_ctx.Detach();
  EXPECT_EQ(0, release->Release());

  EXPECT_FALSE(test.nav_manager().HasRequestData());
}

// Downloads a document asynchronously and then verifies that the downloaded
// contents were cached and the cache contents are correct.
TEST_F(UrlmonMonikerTest, BindToStorageSwitchContent) {
  const wchar_t test_url[] = L"http://localhost:43210/";
  UrlmonMonikerTestManager test(test_url);
  UrlmonMonikerTestCallback callback(&test);

  test_server::SimpleWebServer server(43210);
  test_server::SimpleResponse default_response("/", kTestContent);
  server.AddResponse(&default_response);

  callback.SetCallbackExpectations(
      UrlmonMonikerTestCallback::REQUEST_ASYNCHRONOUS, INET_E_TERMINATED_BIND,
      true);

  HRESULT hr = callback.CreateUrlMonikerAndBindToStorage(test_url, NULL);
  EXPECT_EQ(MK_S_ASYNCHRONOUS, hr);
  test.loop().RunFor(kUrlmonMonikerTimeoutSec);

  scoped_refptr<RequestData> request_data(
      test.nav_manager().GetActiveRequestData(test_url));
  EXPECT_TRUE(request_data != NULL);

  if (request_data) {
    EXPECT_EQ(request_data->GetCachedContentSize(),
              arraysize(kTestContent) - 1);
    ScopedComPtr<IStream> stream;
    request_data->GetResetCachedContentStream(stream.Receive());
    EXPECT_TRUE(stream != NULL);
    if (stream) {
      char buffer[0xffff];
      DWORD read = 0;
      stream->Read(buffer, sizeof(buffer), &read);
      EXPECT_EQ(read, arraysize(kTestContent) - 1);
      EXPECT_EQ(0, memcmp(buffer, kTestContent, read));
    }
  }
}

// Fetches content asynchronously first to cache it and then
// verifies that fetching the cached content the same way works as expected
// and happens synchronously.
TEST_F(UrlmonMonikerTest, BindToStorageCachedContent) {
  const wchar_t test_url[] = L"http://localhost:43210/";
  UrlmonMonikerTestManager test(test_url);
  UrlmonMonikerTestCallback callback(&test);

  test_server::SimpleWebServer server(43210);
  test_server::SimpleResponse default_response("/", kTestContent);
  server.AddResponse(&default_response);

  // First set of expectations.  Download the contents
  // asynchronously.  This should populate the cache so that
  // the second request should be served synchronously without
  // going to the server.
  callback.SetCallbackExpectations(
      UrlmonMonikerTestCallback::REQUEST_ASYNCHRONOUS, INET_E_TERMINATED_BIND,
      true);

  HRESULT hr = callback.CreateUrlMonikerAndBindToStorage(test_url, NULL);
  EXPECT_EQ(MK_S_ASYNCHRONOUS, hr);
  test.loop().RunFor(kUrlmonMonikerTimeoutSec);

  scoped_refptr<RequestData> request_data(
      test.nav_manager().GetActiveRequestData(test_url));
  EXPECT_TRUE(request_data != NULL);

  if (request_data) {
    // This time, just accept the content as normal.
    UrlmonMonikerTestCallback callback2(&test);
    callback2.SetCallbackExpectations(
        UrlmonMonikerTestCallback::EXPECT_NO_CALL, S_OK, false);
    hr = callback2.CreateUrlMonikerAndBindToStorage(test_url, NULL);
    // S_OK means that the operation completed synchronously.
    // Otherwise we'd get MK_S_ASYNCHRONOUS.
    EXPECT_EQ(S_OK, hr);
  }
}

<commit_msg>Disabling BindToStorageSwitchContent while I fix it.<commit_after>// Copyright (c) 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.

#include <atlbase.h>
#include <atlcom.h>

#include "base/scoped_comptr_win.h"
#include "base/thread.h"
#include "chrome_frame/bho.h"
#include "chrome_frame/urlmon_moniker.h"
#include "chrome_frame/test/test_server.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
#include "chrome_frame/test/urlmon_moniker_tests.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
#include "testing/gmock_mutant.h"

using testing::_;
using testing::CreateFunctor;
using testing::Eq;
using testing::Invoke;
using testing::SetArgumentPointee;
using testing::StrEq;
using testing::Return;
using testing::WithArg;
using testing::WithArgs;

static int kUrlmonMonikerTimeoutSec = 5;

namespace {
const char kTestContent[] = ""
    "<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />"
    "Test HTML content";
}  // end namespace

class UrlmonMonikerTest : public testing::Test {
 protected:
  UrlmonMonikerTest() {
  }
};

TEST_F(UrlmonMonikerTest, MonikerPatch) {
  EXPECT_EQ(true, MonikerPatch::Initialize());
  EXPECT_EQ(true, MonikerPatch::Initialize());  // Should be ok to call twice.
  MonikerPatch::Uninitialize();
}

// Runs an HTTP server on a worker thread that has a message loop.
class RunTestServer : public base::Thread {
 public:
  RunTestServer()
      : base::Thread("TestServer"),
      default_response_("/", kTestContent),
      ready_(::CreateEvent(NULL, TRUE, FALSE, NULL)) {
  }

  bool Start() {
    bool ret = StartWithOptions(Options(MessageLoop::TYPE_UI, 0));
    if (ret) {
      message_loop()->PostTask(FROM_HERE,
          NewRunnableFunction(&RunTestServer::StartServer, this));
      wait_until_ready();
    }
    return ret;
  }

  static void StartServer(RunTestServer* me) {
    me->server_.reset(new test_server::SimpleWebServer(43210));
    me->server_->AddResponse(&me->default_response_);
    ::SetEvent(me->ready_);
  }

  bool wait_until_ready() {
    return ::WaitForSingleObject(ready_, kUrlmonMonikerTimeoutSec * 1000)
           == WAIT_OBJECT_0;
  }

 protected:
  scoped_ptr<test_server::SimpleWebServer> server_;
  test_server::SimpleResponse default_response_;
  ScopedHandle ready_;
};

// Helper class for running tests that rely on the NavigationManager.
class UrlmonMonikerTestManager {
 public:
  explicit UrlmonMonikerTestManager(const wchar_t* test_url) {
    mock_mgr_.RegisterThreadInstance();
    mock_mgr_.set_url(test_url);
    EXPECT_EQ(true, MonikerPatch::Initialize());
  }

  ~UrlmonMonikerTestManager() {
    MonikerPatch::Uninitialize();
    mock_mgr_.UnregisterThreadInstance();
  }

  chrome_frame_test::TimedMsgLoop& loop() {
    return loop_;
  }

  TestNavigationManager& nav_manager() {
    return mock_mgr_;
  }

 protected:
  TestNavigationManager mock_mgr_;
  chrome_frame_test::TimedMsgLoop loop_;
};

// Wraps the MockBindStatusCallbackImpl mock object and allows the user
// to specify expectations on the callback object.
class UrlmonMonikerTestCallback {
 public:
  explicit UrlmonMonikerTestCallback(UrlmonMonikerTestManager* mgr)
      : mgr_(mgr) {
  }

  ~UrlmonMonikerTestCallback() {
  }

  typedef enum GetBindInfoExpectations {
    EXPECT_NO_CALL,
    REQUEST_SYNCHRONOUS,
    REQUEST_ASYNCHRONOUS,
  } GET_BIND_INFO_EXPECTATION;

  // Sets gmock expectations for the IBindStatusCallback mock object.
  void SetCallbackExpectations(GetBindInfoExpectations bind_info_handling,
                               HRESULT data_available_response,
                               bool quit_loop_on_stop) {
    EXPECT_CALL(callback_, OnProgress(_, _, _, _))
        .WillRepeatedly(Return(S_OK));

    if (bind_info_handling == REQUEST_ASYNCHRONOUS) {
      EXPECT_CALL(callback_, GetBindInfo(_, _))
          .WillOnce(DoAll(
              WithArgs<0, 1>(
                  Invoke(&MockBindStatusCallbackImpl::SetAsyncBindInfo)),
              Return(S_OK)));
    } else if (bind_info_handling == REQUEST_SYNCHRONOUS) {
      EXPECT_CALL(callback_, GetBindInfo(_, _))
          .WillOnce(DoAll(
              WithArgs<0, 1>(
                  Invoke(&MockBindStatusCallbackImpl::SetSyncBindInfo)),
              Return(S_OK)));
    } else {
      DCHECK(bind_info_handling == EXPECT_NO_CALL);
    }

    EXPECT_CALL(callback_, OnStartBinding(_, _))
        .WillOnce(Return(S_OK));

    EXPECT_CALL(callback_, OnDataAvailable(_, _, _, _))
        .WillRepeatedly(Return(data_available_response));

    if (quit_loop_on_stop) {
      // When expecting asynchronous
      EXPECT_CALL(callback_, OnStopBinding(data_available_response, _))
          .WillOnce(DoAll(QUIT_LOOP(mgr_->loop()), Return(S_OK)));
    } else {
      EXPECT_CALL(callback_, OnStopBinding(data_available_response, _))
          .WillOnce(Return(S_OK));
    }
  }

  HRESULT CreateUrlMonikerAndBindToStorage(const wchar_t* url,
                                           IBindCtx** bind_ctx) {
    ScopedComPtr<IMoniker> moniker;
    HRESULT hr = CreateURLMoniker(NULL, url, moniker.Receive());
    EXPECT_TRUE(moniker != NULL);
    if (moniker) {
      ScopedComPtr<IBindCtx> context;
      ::CreateAsyncBindCtx(0, callback(), NULL, context.Receive());
      DCHECK(context);
      ScopedComPtr<IStream> stream;
      hr = moniker->BindToStorage(context, NULL, IID_IStream,
          reinterpret_cast<void**>(stream.Receive()));
      if (SUCCEEDED(hr) && bind_ctx)
        *bind_ctx = context.Detach();
    }
    return hr;
  }

  IBindStatusCallback* callback() {
    return &callback_;
  }

 protected:
  CComObjectStackEx<MockBindStatusCallbackImpl> callback_;
  UrlmonMonikerTestManager* mgr_;
};

// Tests synchronously binding to a moniker and downloading the target.
TEST_F(UrlmonMonikerTest, BindToStorageSynchronous) {
  const wchar_t test_url[] = L"http://localhost:43210/";
  UrlmonMonikerTestManager test(test_url);
  UrlmonMonikerTestCallback callback(&test);

  RunTestServer server_thread;
  EXPECT_TRUE(server_thread.Start());

  callback.SetCallbackExpectations(
      UrlmonMonikerTestCallback::REQUEST_SYNCHRONOUS, S_OK, false);

  ScopedComPtr<IBindCtx> bind_ctx;
  HRESULT hr = callback.CreateUrlMonikerAndBindToStorage(test_url,
                                                         bind_ctx.Receive());
  // The download should have happened synchronously, so we don't expect
  // MK_S_ASYNCHRONOUS or any errors.
  EXPECT_EQ(S_OK, hr);

  IBindCtx* release = bind_ctx.Detach();
  EXPECT_EQ(0, release->Release());

  server_thread.Stop();

  EXPECT_FALSE(test.nav_manager().HasRequestData());
}

// Tests asynchronously binding to a moniker and downloading the target.
TEST_F(UrlmonMonikerTest, BindToStorageAsynchronous) {
  const wchar_t test_url[] = L"http://localhost:43210/";
  UrlmonMonikerTestManager test(test_url);
  UrlmonMonikerTestCallback callback(&test);

  test_server::SimpleWebServer server(43210);
  test_server::SimpleResponse default_response("/", kTestContent);
  server.AddResponse(&default_response);

  callback.SetCallbackExpectations(
      UrlmonMonikerTestCallback::REQUEST_ASYNCHRONOUS, S_OK, true);

  ScopedComPtr<IBindCtx> bind_ctx;
  HRESULT hr = callback.CreateUrlMonikerAndBindToStorage(test_url,
                                                         bind_ctx.Receive());
  EXPECT_EQ(MK_S_ASYNCHRONOUS, hr);
  test.loop().RunFor(kUrlmonMonikerTimeoutSec);

  IBindCtx* release = bind_ctx.Detach();
  EXPECT_EQ(0, release->Release());

  EXPECT_FALSE(test.nav_manager().HasRequestData());
}

// Downloads a document asynchronously and then verifies that the downloaded
// contents were cached and the cache contents are correct.
// TODO(tommi): Fix and re-enable.
//  http://code.google.com/p/chromium/issues/detail?id=39415
TEST_F(UrlmonMonikerTest, DISABLED_BindToStorageSwitchContent) {
  const wchar_t test_url[] = L"http://localhost:43210/";
  UrlmonMonikerTestManager test(test_url);
  UrlmonMonikerTestCallback callback(&test);

  test_server::SimpleWebServer server(43210);
  test_server::SimpleResponse default_response("/", kTestContent);
  server.AddResponse(&default_response);

  callback.SetCallbackExpectations(
      UrlmonMonikerTestCallback::REQUEST_ASYNCHRONOUS, INET_E_TERMINATED_BIND,
      true);

  HRESULT hr = callback.CreateUrlMonikerAndBindToStorage(test_url, NULL);
  EXPECT_EQ(MK_S_ASYNCHRONOUS, hr);
  test.loop().RunFor(kUrlmonMonikerTimeoutSec);

  scoped_refptr<RequestData> request_data(
      test.nav_manager().GetActiveRequestData(test_url));
  EXPECT_TRUE(request_data != NULL);

  if (request_data) {
    EXPECT_EQ(request_data->GetCachedContentSize(),
              arraysize(kTestContent) - 1);
    ScopedComPtr<IStream> stream;
    request_data->GetResetCachedContentStream(stream.Receive());
    EXPECT_TRUE(stream != NULL);
    if (stream) {
      char buffer[0xffff];
      DWORD read = 0;
      stream->Read(buffer, sizeof(buffer), &read);
      EXPECT_EQ(read, arraysize(kTestContent) - 1);
      EXPECT_EQ(0, memcmp(buffer, kTestContent, read));
    }
  }
}

// Fetches content asynchronously first to cache it and then
// verifies that fetching the cached content the same way works as expected
// and happens synchronously.
TEST_F(UrlmonMonikerTest, BindToStorageCachedContent) {
  const wchar_t test_url[] = L"http://localhost:43210/";
  UrlmonMonikerTestManager test(test_url);
  UrlmonMonikerTestCallback callback(&test);

  test_server::SimpleWebServer server(43210);
  test_server::SimpleResponse default_response("/", kTestContent);
  server.AddResponse(&default_response);

  // First set of expectations.  Download the contents
  // asynchronously.  This should populate the cache so that
  // the second request should be served synchronously without
  // going to the server.
  callback.SetCallbackExpectations(
      UrlmonMonikerTestCallback::REQUEST_ASYNCHRONOUS, INET_E_TERMINATED_BIND,
      true);

  HRESULT hr = callback.CreateUrlMonikerAndBindToStorage(test_url, NULL);
  EXPECT_EQ(MK_S_ASYNCHRONOUS, hr);
  test.loop().RunFor(kUrlmonMonikerTimeoutSec);

  scoped_refptr<RequestData> request_data(
      test.nav_manager().GetActiveRequestData(test_url));
  EXPECT_TRUE(request_data != NULL);

  if (request_data) {
    // This time, just accept the content as normal.
    UrlmonMonikerTestCallback callback2(&test);
    callback2.SetCallbackExpectations(
        UrlmonMonikerTestCallback::EXPECT_NO_CALL, S_OK, false);
    hr = callback2.CreateUrlMonikerAndBindToStorage(test_url, NULL);
    // S_OK means that the operation completed synchronously.
    // Otherwise we'd get MK_S_ASYNCHRONOUS.
    EXPECT_EQ(S_OK, hr);
  }
}

<|endoftext|>