From 6817a52ea20a66896d5deed95ef798941b31d08b Mon Sep 17 00:00:00 2001 From: Ashton Larkin Date: Mon, 30 Nov 2020 11:18:58 -0500 Subject: [PATCH 01/21] Clarify how sim time is interpreted in a System's step (#467) Signed-off-by: Ashton Larkin --- include/ignition/gazebo/System.hh | 27 +++++++++++++++++++-------- tutorials/create_system_plugins.md | 11 +++++++---- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/include/ignition/gazebo/System.hh b/include/ignition/gazebo/System.hh index fc2a3403c1..f8ef47ed01 100644 --- a/include/ignition/gazebo/System.hh +++ b/include/ignition/gazebo/System.hh @@ -44,21 +44,32 @@ namespace ignition /// will only operate on an Entity if it has all of the required /// Components. /// - /// Systems are executed in three phases: + /// Systems are executed in three phases, with each phase for a given step + /// corresponding to the entities at time UpdateInfo::simTime: /// * PreUpdate - /// * Has read-write access to world entities and components - /// * Executed with simulation time at (t0) + /// * Has read-write access to world entities and components. + /// * This is where systems say what they'd like to happen at time + /// UpdateInfo::simTime. /// * Can be used to modify state before physics runs, for example for /// applying control signals or performing network syncronization. /// * Update - /// * Has read-write access to world entities and components - /// * Responsible for propagating time from (t0) to (t0 + dt) - /// * Used for physics simulation step + /// * Has read-write access to world entities and components. + /// * Used for physics simulation step (i.e., simulates what happens at + /// time UpdateInfo::simTime). /// * PostUpdate - /// * Has read-only access to world entities and components - /// * Executed with simulation time at (t0 + dt) + /// * Has read-only access to world entities and components. + /// * Captures everything that happened at time UpdateInfo::simTime. /// * Used to read out results at the end of a simulation step to be used /// for sensor or controller updates. + /// + /// It's important to note that UpdateInfo::simTime does not refer to the + /// current time, but the time reached after the PreUpdate and Update calls + /// have finished. So, if any of the *Update functions are called with + /// simulation paused, time does not advance, which means the time reached + /// after PreUpdate and Update is the same as the starting time. This + /// explains why UpdateInfo::simTime is initially 0 if simulation is started + /// paused, while UpdateInfo::simTime is initially UpdateInfo::dt if + /// simulation is started un-paused. class IGNITION_GAZEBO_VISIBLE System { /// \brief Constructor diff --git a/tutorials/create_system_plugins.md b/tutorials/create_system_plugins.md index 283e73a222..86f5420aab 100644 --- a/tutorials/create_system_plugins.md +++ b/tutorials/create_system_plugins.md @@ -12,17 +12,20 @@ there are currently three additional available interfaces: 1. ISystemPreUpdate 1. Has read-write access to world entities and components. - 2. Executed with simulation time at (t0). + 2. This is where systems say what they'd like to happen at time ignition::gazebo::UpdateInfo::simTime. 3. Can be used to modify state before physics runs, for example for applying control signals or performing network synchronization. 2. ISystemUpdate 1. Has read-write access to world entities and components. - 2. Responsible for propagating time from (t0) to (t0 + dt). - 3. Used for physics simulation step. + 2. Used for physics simulation step (i.e., simulates what happens at time ignition::gazebo::UpdateInfo::simTime). 3. ISystemPostUpdate 1. Has read-only access to world entities and components. - 2. Executed with simulation time at (t0 + dt). + 2. Captures everything that happened at time ignition::gazebo::UpdateInfo::simTime. 3. Used to read out results at the end of a simulation step to be used for sensor or controller updates. +It's important to note that ignition::gazebo::UpdateInfo::simTime does not refer to the current time, but the time reached after the `PreUpdate` and `Update` calls have finished. +So, if any of the `*Update` functions are called with simulation paused, time does not advance, which means the time reached after `PreUpdate` and `Update` is the same as the starting time. +This explains why ignition::gazebo::UpdateInfo::simTime is initially 0 if simulation is started paused, while ignition::gazebo::UpdateInfo::simTime is initially ignition::gazebo::UpdateInfo::dt if simulation is started un-paused. + Systems that are only used to read the current state of the world (sensors, graphics, and rendering) should implement `ISystemPostUpdate`. From 7643e7b3c3f7efd39b41c1e8c074180c793075c9 Mon Sep 17 00:00:00 2001 From: "G.Doisy" Date: Sat, 19 Dec 2020 18:51:21 +0100 Subject: [PATCH 02/21] add frame_id and child_frame_id attribute support for DiffDrive (#361) Add configuration of the odom frame_id and child_frame_id fields from sdf attributes and Signed-off-by: Guillaume Signed-off-by: Guillaume Doisy --- src/systems/diff_drive/DiffDrive.cc | 35 ++- test/integration/diff_drive_system.cc | 107 +++++++++ test/worlds/diff_drive_custom_frame_id.sdf | 245 +++++++++++++++++++++ 3 files changed, 384 insertions(+), 3 deletions(-) create mode 100644 test/worlds/diff_drive_custom_frame_id.sdf diff --git a/src/systems/diff_drive/DiffDrive.cc b/src/systems/diff_drive/DiffDrive.cc index 9c9140c55d..496b6cd50f 100644 --- a/src/systems/diff_drive/DiffDrive.cc +++ b/src/systems/diff_drive/DiffDrive.cc @@ -136,6 +136,12 @@ class ignition::gazebo::systems::DiffDrivePrivate /// \brief A mutex to protect the target velocity command. public: std::mutex mutex; + + /// \brief frame_id from sdf. + public: std::string sdfFrameId; + + /// \brief child_frame_id from sdf. + public: std::string sdfChildFrameId; }; ////////////////////////////////////////////////// @@ -265,6 +271,12 @@ void DiffDrive::Configure(const Entity &_entity, this->dataPtr->odomPub = this->dataPtr->node.Advertise( odomTopic); + if (_sdf->HasElement("frame_id")) + this->dataPtr->sdfFrameId = _sdf->Get("frame_id"); + + if (_sdf->HasElement("child_frame_id")) + this->dataPtr->sdfChildFrameId = _sdf->Get("child_frame_id"); + ignmsg << "DiffDrive subscribing to twist messages on [" << topic << "]" << std::endl; } @@ -427,16 +439,33 @@ void DiffDrivePrivate::UpdateOdometry(const ignition::gazebo::UpdateInfo &_info, // Set the frame id. auto frame = msg.mutable_header()->add_data(); frame->set_key("frame_id"); - frame->add_value(this->model.Name(_ecm) + "/odom"); + if (this->sdfFrameId.empty()) + { + frame->add_value(this->model.Name(_ecm) + "/odom"); + } + else + { + frame->add_value(this->sdfFrameId); + } std::optional linkName = this->canonicalLink.Name(_ecm); - if (linkName) + if (this->sdfChildFrameId.empty()) + { + if (linkName) + { + auto childFrame = msg.mutable_header()->add_data(); + childFrame->set_key("child_frame_id"); + childFrame->add_value(this->model.Name(_ecm) + "/" + *linkName); + } + } + else { auto childFrame = msg.mutable_header()->add_data(); childFrame->set_key("child_frame_id"); - childFrame->add_value(this->model.Name(_ecm) + "/" + *linkName); + childFrame->add_value(this->sdfChildFrameId); } + // Publish the message this->odomPub.Publish(msg); } diff --git a/test/integration/diff_drive_system.cc b/test/integration/diff_drive_system.cc index 1a1d2888ff..2d4da67079 100644 --- a/test/integration/diff_drive_system.cc +++ b/test/integration/diff_drive_system.cc @@ -310,6 +310,113 @@ TEST_P(DiffDriveTest, SkidPublishCmd) EXPECT_LT(poses[0].Rot().Z(), poses[3999].Rot().Z()); } +///////////////////////////////////////////////// +TEST_P(DiffDriveTest, OdomFrameId) +{ + // Start server + ServerConfig serverConfig; + serverConfig.SetSdfFile(std::string(PROJECT_SOURCE_PATH) + + "/test/worlds/diff_drive.sdf"); + + Server server(serverConfig); + EXPECT_FALSE(server.Running()); + EXPECT_FALSE(*server.Running(0)); + + server.SetUpdatePeriod(0ns); + + unsigned int odomPosesCount = 0; + std::function odomCb = + [&odomPosesCount](const msgs::Odometry &_msg) + { + ASSERT_TRUE(_msg.has_header()); + ASSERT_TRUE(_msg.header().has_stamp()); + + ASSERT_GT(_msg.header().data_size(), 1); + + EXPECT_STREQ(_msg.header().data(0).key().c_str(), "frame_id"); + EXPECT_STREQ( + _msg.header().data(0).value().Get(0).c_str(), "vehicle/odom"); + + EXPECT_STREQ(_msg.header().data(1).key().c_str(), "child_frame_id"); + EXPECT_STREQ( + _msg.header().data(1).value().Get(0).c_str(), "vehicle/chassis"); + + odomPosesCount++; + }; + + transport::Node node; + auto pub = node.Advertise("/model/vehicle/cmd_vel"); + node.Subscribe("/model/vehicle/odometry", odomCb); + + msgs::Twist msg; + msgs::Set(msg.mutable_linear(), math::Vector3d(0.5, 0, 0)); + msgs::Set(msg.mutable_angular(), math::Vector3d(0.0, 0, 0.2)); + + pub.Publish(msg); + + server.Run(true, 100, false); + + int sleep = 0; + int maxSleep = 30; + for (; odomPosesCount < 5 && sleep < maxSleep; ++sleep) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + ASSERT_NE(maxSleep, sleep); + + EXPECT_EQ(5u, odomPosesCount); +} + +///////////////////////////////////////////////// +TEST_P(DiffDriveTest, OdomCustomFrameId) +{ + // Start server + ServerConfig serverConfig; + serverConfig.SetSdfFile(std::string(PROJECT_SOURCE_PATH) + + "/test/worlds/diff_drive_custom_frame_id.sdf"); + + Server server(serverConfig); + EXPECT_FALSE(server.Running()); + EXPECT_FALSE(*server.Running(0)); + + server.SetUpdatePeriod(0ns); + + unsigned int odomPosesCount = 0; + std::function odomCb = + [&odomPosesCount](const msgs::Odometry &_msg) + { + ASSERT_TRUE(_msg.has_header()); + ASSERT_TRUE(_msg.header().has_stamp()); + + ASSERT_GT(_msg.header().data_size(), 1); + + EXPECT_STREQ(_msg.header().data(0).key().c_str(), "frame_id"); + EXPECT_STREQ(_msg.header().data(0).value().Get(0).c_str(), "odom"); + + EXPECT_STREQ(_msg.header().data(1).key().c_str(), "child_frame_id"); + EXPECT_STREQ( + _msg.header().data(1).value().Get(0).c_str(), "base_footprint"); + + odomPosesCount++; + }; + + transport::Node node; + auto pub = node.Advertise("/model/vehicle/cmd_vel"); + node.Subscribe("/model/vehicle/odometry", odomCb); + + server.Run(true, 100, false); + + int sleep = 0; + int maxSleep = 30; + for (; odomPosesCount < 5 && sleep < maxSleep; ++sleep) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + ASSERT_NE(maxSleep, sleep); + + EXPECT_EQ(5u, odomPosesCount); +} + // Run multiple times INSTANTIATE_TEST_CASE_P(ServerRepeat, DiffDriveTest, ::testing::Range(1, 2)); diff --git a/test/worlds/diff_drive_custom_frame_id.sdf b/test/worlds/diff_drive_custom_frame_id.sdf new file mode 100644 index 0000000000..073bfc41b8 --- /dev/null +++ b/test/worlds/diff_drive_custom_frame_id.sdf @@ -0,0 +1,245 @@ + + + + + + 0.001 + 1.0 + + + + + + true + 0 0 10 0 0 0 + 1 1 1 1 + 0.5 0.5 0.5 1 + + 1000 + 0.9 + 0.01 + 0.001 + + -0.5 0.1 -0.9 + + + + true + + + + + 0 0 1 + + + + + + + 0 0 1 + 100 100 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + + + 0 0 0.325 0 -0 0 + + + -0.151427 -0 0.175 0 -0 0 + + 1.14395 + + 0.126164 + 0 + 0 + 0.416519 + 0 + 0.481014 + + + + + + 2.01142 1 0.568726 + + + + 0.5 0.5 1.0 1 + 0.5 0.5 1.0 1 + 0.0 0.0 1.0 1 + + + + + + 2.01142 1 0.568726 + + + + + + + 0.554283 0.625029 -0.025 -1.5707 0 0 + + 2 + + 0.145833 + 0 + 0 + 0.145833 + 0 + 0.125 + + + + + + 0.3 + + + + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + + + + + + 0.3 + + + + + + + 0.554282 -0.625029 -0.025 -1.5707 0 0 + + 2 + + 0.145833 + 0 + 0 + 0.145833 + 0 + 0.125 + + + + + + 0.3 + + + + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + + + + + + 0.3 + + + + + + + -0.957138 -0 -0.125 0 -0 0 + + 1 + + 0.1 + 0 + 0 + 0.1 + 0 + 0.1 + + + + + + 0.2 + + + + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + + + + + + 0.2 + + + + + + + chassis + left_wheel + + 0 0 1 + + -1.79769e+308 + 1.79769e+308 + + + + + + chassis + right_wheel + + 0 0 1 + + -1.79769e+308 + 1.79769e+308 + + + + + + chassis + caster + + + + left_wheel_joint + right_wheel_joint + 1.25 + 0.3 + 1 + 0.5 + odom + base_footprint + + + + + + + + + + + From 478dea615a72f3ae13a1788389157da245dd6121 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Mon, 21 Dec 2020 13:04:56 -0800 Subject: [PATCH 03/21] Add ability to record video based on sim time (#414) * add ability to record video from gui camera using sim time Signed-off-by: Ian Chen * add msg Signed-off-by: Ian Chen * use QueryBoolText Signed-off-by: Ian Chen Co-authored-by: Nate Koenig Co-authored-by: Louise Poubel --- .../ignition/gazebo/rendering/RenderUtil.hh | 5 ++ src/gui/plugins/scene3d/Scene3D.cc | 47 ++++++++++++++++++- src/gui/plugins/scene3d/Scene3D.hh | 8 ++++ src/rendering/RenderUtil.cc | 7 +++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/include/ignition/gazebo/rendering/RenderUtil.hh b/include/ignition/gazebo/rendering/RenderUtil.hh index 72a0055e79..aa66219bb3 100644 --- a/include/ignition/gazebo/rendering/RenderUtil.hh +++ b/include/ignition/gazebo/rendering/RenderUtil.hh @@ -119,6 +119,11 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// Returns reference to the marker manager. public: class MarkerManager &MarkerManager(); + /// \brief Get simulation time that the current rendering state corresponds + /// to + /// \returns Simulation time. + public: std::chrono::steady_clock::duration SimTime() const; + /// \brief Set the entity being selected /// \param[in] _node Node representing the selected entity /// \TODO(anyone) Make const ref when merging forward diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index 18d0034fea..dfec2323c0 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -198,6 +198,10 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \brief Path to save the recorded video public: std::string recordVideoSavePath; + /// \brief Use sim time as timestamp during video recording + /// By default (false), video encoding is done using real time. + public: bool recordVideoUseSimTime = false; + /// \brief Target to move the user camera to public: std::string moveToTarget; @@ -489,12 +493,22 @@ void IgnRenderer::Render() if (this->dataPtr->videoEncoder.IsEncoding()) { this->dataPtr->camera->Copy(this->dataPtr->cameraImage); + + std::chrono::steady_clock::time_point t = + std::chrono::steady_clock::now(); + if (this->dataPtr->recordVideoUseSimTime) + { + t = std::chrono::steady_clock::time_point( + this->dataPtr->renderUtil.SimTime()); + } this->dataPtr->videoEncoder.AddFrame( - this->dataPtr->cameraImage.Data(), width, height); + this->dataPtr->cameraImage.Data(), width, height, t); } // Video recorder is idle. Start recording. else { + if (this->dataPtr->recordVideoUseSimTime) + ignmsg << "Recording video using sim time." << std::endl; this->dataPtr->videoEncoder.Start(this->dataPtr->recordVideoFormat, this->dataPtr->recordVideoSavePath, width, height); } @@ -1715,6 +1729,13 @@ void IgnRenderer::SetRecordVideo(bool _record, const std::string &_format, this->dataPtr->recordVideoSavePath = _savePath; } +///////////////////////////////////////////////// +void IgnRenderer::SetRecordVideoUseSimTime(bool _useSimTime) +{ + std::lock_guard lock(this->dataPtr->mutex); + this->dataPtr->recordVideoUseSimTime = _useSimTime; +} + ///////////////////////////////////////////////// void IgnRenderer::SetMoveTo(const std::string &_target) { @@ -2331,6 +2352,23 @@ void Scene3D::LoadConfig(const tinyxml2::XMLElement *_pluginElem) } } + if (auto elem = _pluginElem->FirstChildElement("record_video")) + { + if (auto useSimTimeElem = elem->FirstChildElement("use_sim_time")) + { + bool useSimTime = false; + if (useSimTimeElem->QueryBoolText(&useSimTime) != tinyxml2::XML_SUCCESS) + { + ignerr << "Faild to parse value: " + << useSimTimeElem->GetText() << std::endl; + } + else + { + renderWindow->SetRecordVideoUseSimTime(useSimTime); + } + } + } + if (auto elem = _pluginElem->FirstChildElement("fullscreen")) { auto fullscreen = false; @@ -2815,6 +2853,13 @@ void RenderWindowItem::SetWorldName(const std::string &_name) this->dataPtr->renderThread->ignRenderer.worldName = _name; } +///////////////////////////////////////////////// +void RenderWindowItem::SetRecordVideoUseSimTime(bool _useSimTime) +{ + this->dataPtr->renderThread->ignRenderer.SetRecordVideoUseSimTime( + _useSimTime); +} + ///////////////////////////////////////////////// void RenderWindowItem::OnHovered(const ignition::math::Vector2i &_hoverPos) { diff --git a/src/gui/plugins/scene3d/Scene3D.hh b/src/gui/plugins/scene3d/Scene3D.hh index 48cfdcb11b..cabc05a0a8 100644 --- a/src/gui/plugins/scene3d/Scene3D.hh +++ b/src/gui/plugins/scene3d/Scene3D.hh @@ -206,6 +206,10 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { public: void SetRecordVideo(bool _record, const std::string &_format, const std::string &_savePath); + /// \brief Set whether to record video using sim time as timestamp + /// \param[in] _true True record video using sim time + public: void SetRecordVideoUseSimTime(bool _useSimTime); + /// \brief Move the user camera to move to the speficied target /// \param[in] _target Target to move the camera to public: void SetMoveTo(const std::string &_target); @@ -521,6 +525,10 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { public: void SetRecordVideo(bool _record, const std::string &_format, const std::string &_savePath); + /// \brief Set whether to record video using sim time as timestamp + /// \param[in] _true True record video using sim time + public: void SetRecordVideoUseSimTime(bool _useSimTime); + /// \brief Move the user camera to move to the specified target /// \param[in] _target Target to move the camera to public: void SetMoveTo(const std::string &_target); diff --git a/src/rendering/RenderUtil.cc b/src/rendering/RenderUtil.cc index baad8e79a3..01bcd7644f 100644 --- a/src/rendering/RenderUtil.cc +++ b/src/rendering/RenderUtil.cc @@ -1153,6 +1153,13 @@ MarkerManager &RenderUtil::MarkerManager() return this->dataPtr->markerManager; } +////////////////////////////////////////////////// +std::chrono::steady_clock::duration RenderUtil::SimTime() const +{ + std::lock_guard lock(this->dataPtr->updateMutex); + return this->dataPtr->simTime; +} + ///////////////////////////////////////////////// // NOLINTNEXTLINE void RenderUtil::SetSelectedEntity(rendering::NodePtr _node) From bea08795e2a83858e53e742e7c4026d49341b3cc Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Wed, 23 Dec 2020 09:32:41 -0800 Subject: [PATCH 04/21] Add lockstep mode to video recording (#419) Signed-off-by: Ian Chen Signed-off-by: Louise Poubel Co-authored-by: Nate Koenig Co-authored-by: Louise Poubel --- src/gui/plugins/scene3d/Scene3D.cc | 184 +++++++++++++++++- src/gui/plugins/scene3d/Scene3D.hh | 22 +++ .../scene_broadcaster/SceneBroadcaster.cc | 5 + tutorials.md.in | 1 + .../files/video_recorder/video_recorder.gif | Bin 0 -> 222842 bytes .../files/video_recorder/video_recorder.png | Bin 0 -> 47398 bytes tutorials/video_recorder.md | 107 ++++++++++ 7 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 tutorials/files/video_recorder/video_recorder.gif create mode 100644 tutorials/files/video_recorder/video_recorder.png create mode 100644 tutorials/video_recorder.md diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index dfec2323c0..99bbe5b7d4 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -19,8 +19,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -66,6 +68,11 @@ #include "ignition/gazebo/gui/GuiEvents.hh" #include "ignition/gazebo/rendering/RenderUtil.hh" +/// \brief condition variable for lockstepping video recording +/// todo(anyone) avoid using a global condition variable when we support +/// multiple viewports in the future. +std::condition_variable g_renderCv; + Q_DECLARE_METATYPE(std::string) namespace ignition @@ -202,6 +209,22 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// By default (false), video encoding is done using real time. public: bool recordVideoUseSimTime = false; + /// \brief Lockstep gui with ECM when recording + public: bool recordVideoLockstep = false; + + /// \brief Video recorder bitrate (bps) + public: unsigned int recordVideoBitrate = 2070000; + + /// \brief Previous camera update time during video recording + /// only used in lockstep mode and recording in sim time. + public: std::chrono::steady_clock::time_point recordVideoUpdateTime; + + /// \brief Start tiem of video recording + public: std::chrono::steady_clock::time_point recordStartTime; + + /// \brief Camera pose publisher + public: transport::Node::Publisher recorderStatsPub; + /// \brief Target to move the user camera to public: std::string moveToTarget; @@ -344,6 +367,9 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \brief Render thread public : RenderThread *renderThread = nullptr; + //// \brief Set to true after the renderer is initialized + public: bool rendererInit = false; + //// \brief List of threads public: static QList threads; }; @@ -386,6 +412,19 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \brief Camera pose publisher public: transport::Node::Publisher cameraPosePub; + + /// \brief lockstep ECM updates with rendering + public: bool recordVideoLockstep = false; + + /// \brief True to indicate video recording in progress + public: bool recording = false; + + /// \brief mutex to protect the recording variable + public: std::mutex recordMutex; + + /// \brief mutex to protect the render condition variable + /// Used when recording in lockstep mode. + public: std::mutex renderMutex; }; } } @@ -401,6 +440,13 @@ IgnRenderer::IgnRenderer() : dataPtr(new IgnRendererPrivate) { this->dataPtr->moveToHelper.initCameraPose = this->cameraPose; + + // recorder stats topic + std::string recorderStatsTopic = "/gui/record_video/stats"; + this->dataPtr->recorderStatsPub = + this->dataPtr->node.Advertise(recorderStatsTopic); + ignmsg << "Video recorder stats topic advertised on [" + << recorderStatsTopic << "]" << std::endl; } @@ -469,7 +515,24 @@ void IgnRenderer::Render() } } + // check if recording is in lockstep mode and if it is using sim time + // if so, there is no need to update camera if sim time has not advanced + bool update = true; + if (this->dataPtr->recordVideoLockstep && + this->dataPtr->recordVideoUseSimTime && + this->dataPtr->videoEncoder.IsEncoding()) + { + std::chrono::steady_clock::time_point t = + std::chrono::steady_clock::time_point( + this->dataPtr->renderUtil.SimTime()); + if (t - this->dataPtr->recordVideoUpdateTime == std::chrono::seconds(0)) + update = false; + else + this->dataPtr->recordVideoUpdateTime = t; + } + // update and render to texture + if (update) { IGN_PROFILE("IgnRenderer::Render Update camera"); this->dataPtr->camera->Update(); @@ -501,16 +564,51 @@ void IgnRenderer::Render() t = std::chrono::steady_clock::time_point( this->dataPtr->renderUtil.SimTime()); } - this->dataPtr->videoEncoder.AddFrame( + bool frameAdded = this->dataPtr->videoEncoder.AddFrame( this->dataPtr->cameraImage.Data(), width, height, t); + + if (frameAdded) + { + // publish recorder stats + if (this->dataPtr->recordStartTime == + std::chrono::steady_clock::time_point( + std::chrono::duration(std::chrono::seconds(0)))) + { + // start time, i.e. time when first frame is added + this->dataPtr->recordStartTime = t; + } + + std::chrono::steady_clock::duration dt; + dt = t - this->dataPtr->recordStartTime; + int64_t sec, nsec; + std::tie(sec, nsec) = ignition::math::durationToSecNsec(dt); + msgs::Time msg; + msg.set_sec(sec); + msg.set_nsec(nsec); + this->dataPtr->recorderStatsPub.Publish(msg); + } } // Video recorder is idle. Start recording. else { if (this->dataPtr->recordVideoUseSimTime) ignmsg << "Recording video using sim time." << std::endl; + if (this->dataPtr->recordVideoLockstep) + { + ignmsg << "Recording video in lockstep mode" << std::endl; + if (!this->dataPtr->recordVideoUseSimTime) + { + ignwarn << "It is recommended to set to true " + << "when recording video in lockstep mode." << std::endl; + } + } + ignmsg << "Recording video using bitrate: " + << this->dataPtr->recordVideoBitrate << std::endl; this->dataPtr->videoEncoder.Start(this->dataPtr->recordVideoFormat, - this->dataPtr->recordVideoSavePath, width, height); + this->dataPtr->recordVideoSavePath, width, height, 25, + this->dataPtr->recordVideoBitrate); + this->dataPtr->recordStartTime = std::chrono::steady_clock::time_point( + std::chrono::duration(std::chrono::seconds(0))); } } else if (this->dataPtr->videoEncoder.IsEncoding()) @@ -708,6 +806,10 @@ void IgnRenderer::Render() ignition::gui::App()->findChild(), &event); } + + // only has an effect in video recording lockstep mode + // this notifes ECM to continue updating the scene + g_renderCv.notify_one(); } ///////////////////////////////////////////////// @@ -1736,6 +1838,20 @@ void IgnRenderer::SetRecordVideoUseSimTime(bool _useSimTime) this->dataPtr->recordVideoUseSimTime = _useSimTime; } +///////////////////////////////////////////////// +void IgnRenderer::SetRecordVideoLockstep(bool _useSimTime) +{ + std::lock_guard lock(this->dataPtr->mutex); + this->dataPtr->recordVideoLockstep = _useSimTime; +} + +///////////////////////////////////////////////// +void IgnRenderer::SetRecordVideoBitrate(unsigned int _bitrate) +{ + std::lock_guard lock(this->dataPtr->mutex); + this->dataPtr->recordVideoBitrate = _bitrate; +} + ///////////////////////////////////////////////// void IgnRenderer::SetMoveTo(const std::string &_target) { @@ -2110,6 +2226,14 @@ void RenderWindowItem::Ready() this->dataPtr->renderThread->start(); this->update(); + + this->dataPtr->rendererInit = true; +} + +///////////////////////////////////////////////// +bool RenderWindowItem::RendererInitialized() const +{ + return this->dataPtr->rendererInit; } ///////////////////////////////////////////////// @@ -2367,6 +2491,35 @@ void Scene3D::LoadConfig(const tinyxml2::XMLElement *_pluginElem) renderWindow->SetRecordVideoUseSimTime(useSimTime); } } + if (auto lockstepElem = elem->FirstChildElement("lockstep")) + { + bool lockstep = false; + if (lockstepElem->QueryBoolText(&lockstep) != tinyxml2::XML_SUCCESS) + { + ignerr << "Failed to parse value: " + << lockstepElem->GetText() << std::endl; + } + else + { + renderWindow->SetRecordVideoLockstep(lockstep); + } + } + if (auto bitrateElem = elem->FirstChildElement("bitrate")) + { + unsigned int bitrate = 0u; + std::stringstream bitrateStr; + bitrateStr << std::string(bitrateElem->GetText()); + bitrateStr >> bitrate; + if (bitrate > 0u) + { + renderWindow->SetRecordVideoBitrate(bitrate); + } + else + { + ignerr << "Video recorder bitrate must be larger than 0" + << std::endl; + } + } } if (auto elem = _pluginElem->FirstChildElement("fullscreen")) @@ -2484,6 +2637,16 @@ void Scene3D::Update(const UpdateInfo &_info, this->dataPtr->cameraPosePub.Publish(poseMsg); } this->dataPtr->renderUtil->UpdateFromECM(_info, _ecm); + + // check if video recording is enabled and if we need to lock step + // ECM updates with GUI rendering during video recording + std::unique_lock lock(this->dataPtr->recordMutex); + if (this->dataPtr->recording && this->dataPtr->recordVideoLockstep && + renderWindow->RendererInitialized()) + { + std::unique_lock lock2(this->dataPtr->renderMutex); + g_renderCv.wait(lock2); + } } ///////////////////////////////////////////////// @@ -2507,6 +2670,9 @@ bool Scene3D::OnRecordVideo(const msgs::VideoRecord &_msg, renderWindow->SetRecordVideo(record, _msg.format(), _msg.save_filename()); _res.set_data(true); + + std::unique_lock lock(this->dataPtr->recordMutex); + this->dataPtr->recording = record; return true; } @@ -2860,6 +3026,20 @@ void RenderWindowItem::SetRecordVideoUseSimTime(bool _useSimTime) _useSimTime); } +///////////////////////////////////////////////// +void RenderWindowItem::SetRecordVideoLockstep(bool _lockstep) +{ + this->dataPtr->renderThread->ignRenderer.SetRecordVideoLockstep( + _lockstep); +} + +///////////////////////////////////////////////// +void RenderWindowItem::SetRecordVideoBitrate(unsigned int _bitrate) +{ + this->dataPtr->renderThread->ignRenderer.SetRecordVideoBitrate( + _bitrate); +} + ///////////////////////////////////////////////// void RenderWindowItem::OnHovered(const ignition::math::Vector2i &_hoverPos) { diff --git a/src/gui/plugins/scene3d/Scene3D.hh b/src/gui/plugins/scene3d/Scene3D.hh index cabc05a0a8..112de34a2b 100644 --- a/src/gui/plugins/scene3d/Scene3D.hh +++ b/src/gui/plugins/scene3d/Scene3D.hh @@ -210,6 +210,14 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \param[in] _true True record video using sim time public: void SetRecordVideoUseSimTime(bool _useSimTime); + /// \brief Set whether to record video in lockstep mode + /// \param[in] _true True to record video in lockstep mode + public: void SetRecordVideoLockstep(bool _lockstep); + + /// \brief Set video recorder bitrate in bps + /// \param[in] _bitrate Bit rate to set to + public: void SetRecordVideoBitrate(unsigned int _bitrate); + /// \brief Move the user camera to move to the speficied target /// \param[in] _target Target to move the camera to public: void SetMoveTo(const std::string &_target); @@ -529,6 +537,14 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \param[in] _true True record video using sim time public: void SetRecordVideoUseSimTime(bool _useSimTime); + /// \brief Set whether to record video in lockstep mode + /// \param[in] _true True to record video in lockstep mode + public: void SetRecordVideoLockstep(bool _lockstep); + + /// \brief Set video recorder bitrate in bps + /// \param[in] _bitrate Bit rate to set to + public: void SetRecordVideoBitrate(unsigned int _bitrate); + /// \brief Move the user camera to move to the specified target /// \param[in] _target Target to move the camera to public: void SetMoveTo(const std::string &_target); @@ -610,6 +626,12 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// the render window. public: void OnHovered(const ignition::math::Vector2i &_hoverPos); + /// \brief Get whether the renderer is initialized. The renderer is + /// initialized when the context is created and the render thread is + /// started. + /// \return True if the renderer is initialized. + public: bool RendererInitialized() const; + /// \brief Slot called when thread is ready to be started public Q_SLOTS: void Ready(); diff --git a/src/systems/scene_broadcaster/SceneBroadcaster.cc b/src/systems/scene_broadcaster/SceneBroadcaster.cc index 576a081bc0..9dde20341b 100644 --- a/src/systems/scene_broadcaster/SceneBroadcaster.cc +++ b/src/systems/scene_broadcaster/SceneBroadcaster.cc @@ -226,6 +226,11 @@ void SceneBroadcaster::Configure( auto readHertz = _sdf->Get("dynamic_pose_hertz", 60); this->dataPtr->dyPoseHertz = readHertz.first; + auto stateHerz = _sdf->Get("state_hertz", 60); + this->dataPtr->statePublishPeriod = + std::chrono::duration>( + std::chrono::milliseconds(1000/stateHerz.first)); + // Add to graph { std::lock_guard lock(this->dataPtr->graphMutex); diff --git a/tutorials.md.in b/tutorials.md.in index 6191d0d020..a7f1c5be81 100644 --- a/tutorials.md.in +++ b/tutorials.md.in @@ -22,6 +22,7 @@ Ignition @IGN_DESIGNATION_CAP@ library and how to use the library effectively. * \subpage detachablejoints "Detachable Joints": Creating models that start off rigidly attached and then get detached during simulation. * \subpage triggeredpublisher "Triggered Publisher": Using the TriggeredPublisher system to orchestrate actions in simulation. * \subpage logicalaudiosensor "Logical Audio Sensor": Using the LogicalAudioSensor system to mimic logical audio emission and detection in simulation. +* \subpage videorecorder "Video Recorder": Record videos from the 3D render window. **Migration from Gazebo classic** diff --git a/tutorials/files/video_recorder/video_recorder.gif b/tutorials/files/video_recorder/video_recorder.gif new file mode 100644 index 0000000000000000000000000000000000000000..e9e9b28dc9351a56f6f34434f41b1e1d10bf0952 GIT binary patch literal 222842 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 gB)_XA8a{x_M%Mjc+ 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 aK;}Nr2$)4nYTZw*e-&1-BjYfA`~C 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%0D34+>^}tlJo^*SaD)o}HIOa{t>O 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 SnR;Nr$9pLy$!c-q;Qt3LxtI(9 literal 0 HcmV?d00001 diff --git a/tutorials/video_recorder.md b/tutorials/video_recorder.md new file mode 100644 index 0000000000..54b8fbe519 --- /dev/null +++ b/tutorials/video_recorder.md @@ -0,0 +1,107 @@ +\page videorecorder Video Recorder + +## Using the video recorder plugin + +Ignition Gazebo offers a video recorder tool for recording videos from the 3D +scene. The recorder tool is available as a GUI plugin. To open this plugin, +first launch Ignition Gazebo and select the ellipsis menu on top right +(3 dots menu), and scroll down to find the `Video Recorder` option. Click on the +plugin to open the Video Recorder tool. Alternatively, launch the demo world in +Ignition Gazebo that already has this plugin included in the GUI. + +``` +ign gazebo -v 4 video_record_dbl_pendulum.sdf +``` + +In this plugin, you should see a single button with a video recorder icon. +Clicking on the button gives you the video format options that are available. + +@image html files/video_recorder/video_recorder.png + +Once an option is selected, recording starts immediately as indicated by +a flashing video recorder icon. At anytime that you wish to stop recording, +click on the flashing icon and select `Stop`. A file dialog window should pop up +and let you select the path to save the recorded video in. + +Playback the video you just saved and you should notice that the resolution +of the video is based on the size of your 3D scene window. So if you wish +to record the video in a different size, make sure to configure the GUI +window prior to recording. + +@image html files/video_recorder/video_recorder.gif + + +## Video recorder configurations + +A few video recorder parameters can be specified using GUI configurations, see +the [GUI Configuration](gui_config.html) tutorial for more information. +If you launched Ignition Gazebo with the +`video_record_dbl_pendulum.sdf` demo world, the GUI configurations are embedded +in the world SDF file so you will need to download a copy of the +[sdf file](https://raw.githubusercontent.com/ignitionrobotics/ign-gazebo/ign-gazebo3/examples/worlds/video_record_dbl_pendulum.sdf). +and modify the GUI configuration in that file. On the other hand, if you +launched Ignition Gazebo with a world file that does not have GUI +configurations, you will need to specify the settings in +`$HOME/.ignition/gazebo/gui.config`. + +Recall that videos are recorded from the 3D scene, we will to set the video +configurations in the 3D scene plugin. Here is an example of the +Scene 3D plugin with custom video recorder settings: + +```xml + + + 3D View + false + docked + + + ogre2 + scene + 0.4 0.4 0.4 + 0.8 0.8 0.8 + 6 0 6 0 0.5 3.14 + + + true + true + 4000000 + + + +``` + +Options are: + +* **use_sim_time**: Values are `[true|false]`. Record videos based on sim time, +i.e. each frame encoded into the video will be timestamped using sim time. +For example, if a complex simulation was running at half of real time speed, and +`` is set to true, video playback should ignore delays due +to low Real Time Factor (RTF) and plays back video as if RTF was 1.0. +By default, the value is `false`, which means the videos are recorded based +on real time. + +* **lockstep**: Values are `[true|false]`. Lockstep simulation for video +recording. This forces the GUI to pause and only process a new state update +from the server until the video recorder finishes encoding the current frame. +This ensures that the video recorder does not miss any updates / frames in the +resulting video. This configuration makes more sense when used with +`` set to `true`, in which case it produces smooth videos +with exact timing, i.e. if you record simulation for 1 minute sim time, +the resulting video should be also 1 minute long (+/- 1 second due to encoder +settings). Defaults to `false`. Note: the server publishes states at 60Hz +and the video recorder records at 25 FPS so it also makes sense to update the +Scene Broadcaster system to only publish states at 25Hz. You can do this by +going to the world SDF file, locate the +`ignition::gazebo::systems::SceneBroadcaster` system, and set the +`` parameter: + +```xml + + 25 + +``` + +* **bitrate**: Video encoding bitrate in bps. This affects the quality of the +generated video. The default bitrate is 2Mbps. From 43412b50f906ca9db67cff9e14fe02e0d5501421 Mon Sep 17 00:00:00 2001 From: John Shepherd Date: Mon, 28 Dec 2020 16:44:55 -0800 Subject: [PATCH 05/21] Disable right click menu when using measuring tool (#458) Signed-off-by: John Shepherd Co-authored-by: Louise Poubel --- src/gui/plugins/scene3d/Scene3D.cc | 50 +++++++++++++++++++++ src/gui/plugins/scene3d/Scene3D.hh | 13 ++++++ src/gui/plugins/tape_measure/TapeMeasure.cc | 32 +++++++++++++ 3 files changed, 95 insertions(+) diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index 99bbe5b7d4..b6e3dc9af1 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -264,6 +264,10 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// resource with the shapes plugin or not public: bool isPlacing = false; + /// \brief Atomic bool indicating whether the dropdown menu + /// is currently enabled or disabled. + public: std::atomic_bool dropdownMenuEnabled = true; + /// \brief The SDF string of the resource to be used with plugins that spawn /// entities. public: std::string spawnSdfString; @@ -900,6 +904,7 @@ void IgnRenderer::HandleMouseEvent() std::lock_guard lock(this->dataPtr->mutex); this->BroadcastHoverPos(); this->BroadcastLeftClick(); + this->BroadcastRightClick(); this->HandleMouseContextMenu(); this->HandleModelPlacement(); this->HandleMouseTransformControl(); @@ -936,6 +941,26 @@ void IgnRenderer::BroadcastLeftClick() } } +///////////////////////////////////////////////// +void IgnRenderer::BroadcastRightClick() +{ + if (this->dataPtr->mouseEvent.Button() == common::MouseEvent::RIGHT && + this->dataPtr->mouseEvent.Type() == common::MouseEvent::RELEASE && + !this->dataPtr->mouseEvent.Dragging() && this->dataPtr->mouseDirty) + { + // If the dropdown menu is disabled, quash the mouse event + if (!this->dataPtr->dropdownMenuEnabled) + this->dataPtr->mouseDirty = false; + + math::Vector3d pos = this->ScreenToScene(this->dataPtr->mouseEvent.Pos()); + + ignition::gui::events::RightClickToScene rightClickToSceneEvent(pos); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &rightClickToSceneEvent); + } +} + ///////////////////////////////////////////////// void IgnRenderer::HandleMouseContextMenu() { @@ -1821,6 +1846,12 @@ void IgnRenderer::SetModelPath(const std::string &_filePath) this->dataPtr->spawnSdfPath = _filePath; } +///////////////////////////////////////////////// +void IgnRenderer::SetDropdownMenuEnabled(bool _enableDropdownMenu) +{ + this->dataPtr->dropdownMenuEnabled = _enableDropdownMenu; +} + ///////////////////////////////////////////////// void IgnRenderer::SetRecordVideo(bool _record, const std::string &_format, const std::string &_savePath) @@ -2901,6 +2932,18 @@ bool Scene3D::eventFilter(QObject *_obj, QEvent *_event) renderWindow->SetModelPath(spawnPreviewPathEvent->FilePath()); } } + else if (_event->type() == + ignition::gui::events::DropdownMenuEnabled::kType) + { + auto dropdownMenuEnabledEvent = + reinterpret_cast(_event); + if (dropdownMenuEnabledEvent) + { + auto renderWindow = this->PluginItem()->findChild(); + renderWindow->SetDropdownMenuEnabled( + dropdownMenuEnabledEvent->MenuEnabled()); + } + } // Standard event processing return QObject::eventFilter(_obj, _event); @@ -2932,6 +2975,13 @@ void RenderWindowItem::SetModelPath(const std::string &_filePath) this->dataPtr->renderThread->ignRenderer.SetModelPath(_filePath); } +///////////////////////////////////////////////// +void RenderWindowItem::SetDropdownMenuEnabled(bool _enableDropdownMenu) +{ + this->dataPtr->renderThread->ignRenderer.SetDropdownMenuEnabled( + _enableDropdownMenu); +} + ///////////////////////////////////////////////// void RenderWindowItem::SetRecordVideo(bool _record, const std::string &_format, const std::string &_savePath) diff --git a/src/gui/plugins/scene3d/Scene3D.hh b/src/gui/plugins/scene3d/Scene3D.hh index 112de34a2b..cf966a4efe 100644 --- a/src/gui/plugins/scene3d/Scene3D.hh +++ b/src/gui/plugins/scene3d/Scene3D.hh @@ -199,6 +199,11 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \param[in] _filePath Sdf path of the model to load in for the user. public: void SetModelPath(const std::string &_filePath); + /// \brief Set if the dropdown menu is enabled or disabled. + /// \param[in] _enableDropdownMenu The boolean to enable or disable + /// the dropdown menu + public: void SetDropdownMenuEnabled(bool _enableDropdownMenu); + /// \brief Set whether to record video /// \param[in] _record True to start video recording, false to stop. /// \param[in] _format Video encoding format: "mp4", "ogv" @@ -369,6 +374,9 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \brief Broadcasts a left click within the scene private: void BroadcastLeftClick(); + /// \brief Broadcasts a right click within the scene + private: void BroadcastRightClick(); + /// \brief Generate a unique entity id. /// \return The unique entity id private: Entity UniqueId(); @@ -526,6 +534,11 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \param[in] _filePath File path of the model to load in for the user. public: void SetModelPath(const std::string &_filePath); + /// \brief Set if the dropdown menu is enabled or disabled. + /// \param[in] _enableDropdownMenu The boolean to enable or disable + /// the menu + public: void SetDropdownMenuEnabled(bool _enableDropdownMenu); + /// \brief Set whether to record video /// \param[in] _record True to start video recording, false to stop. /// \param[in] _format Video encoding format: "mp4", "ogv" diff --git a/src/gui/plugins/tape_measure/TapeMeasure.cc b/src/gui/plugins/tape_measure/TapeMeasure.cc index adbec33d47..882ce7e9c3 100644 --- a/src/gui/plugins/tape_measure/TapeMeasure.cc +++ b/src/gui/plugins/tape_measure/TapeMeasure.cc @@ -127,6 +127,13 @@ void TapeMeasure::Measure() this->Reset(); this->dataPtr->measure = true; QGuiApplication::setOverrideCursor(Qt::CrossCursor); + + // Notify Scene3D to disable the right click menu while we use it to + // cancel our current measuring action + ignition::gui::events::DropdownMenuEnabled dropdownMenuEnabledEvent(false); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &dropdownMenuEnabledEvent); } ///////////////////////////////////////////////// @@ -149,6 +156,13 @@ void TapeMeasure::Reset() this->dataPtr->measure = false; this->newDistance(); QGuiApplication::restoreOverrideCursor(); + + // Notify Scene3D that we are done using the right click, so it can + // re-enable the settings menu + ignition::gui::events::DropdownMenuEnabled dropdownMenuEnabledEvent(true); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &dropdownMenuEnabledEvent); } ///////////////////////////////////////////////// @@ -271,6 +285,15 @@ bool TapeMeasure::eventFilter(QObject *_obj, QEvent *_event) this->dataPtr->startPoint.Distance(this->dataPtr->endPoint); this->newDistance(); QGuiApplication::restoreOverrideCursor(); + + // Notify Scene3D that we are done using the right click, so it can + // re-enable the settings menu + ignition::gui::events::DropdownMenuEnabled + dropdownMenuEnabledEvent(true); + + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &dropdownMenuEnabledEvent); } this->dataPtr->currentId = this->dataPtr->kEndPointId; } @@ -293,6 +316,15 @@ bool TapeMeasure::eventFilter(QObject *_obj, QEvent *_event) this->Reset(); } } + // Cancel the current action if a right click is detected + else if (_event->type() == ignition::gui::events::RightClickToScene::kType) + { + if (this->dataPtr->measure) + { + this->Reset(); + } + } + return QObject::eventFilter(_obj, _event); } From 6fafc9661b896ea39beeb33a08c7e87a41c3569b Mon Sep 17 00:00:00 2001 From: Louise Poubel Date: Wed, 30 Dec 2020 18:22:48 -0800 Subject: [PATCH 06/21] Bump to 3.6.0 (#524) Signed-off-by: Louise Poubel --- CMakeLists.txt | 2 +- Changelog.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ae2a9c6b3..a21de380bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR) #============================================================================ # Initialize the project #============================================================================ -project(ignition-gazebo3 VERSION 3.5.0) +project(ignition-gazebo3 VERSION 3.6.0) #============================================================================ # Find ignition-cmake diff --git a/Changelog.md b/Changelog.md index d077dc3ce6..e9ee76d1a7 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,68 @@ ### Ignition Gazebo 3.X.X (20XX-XX-XX) +### Ignition Gazebo 3.6.0 (2020-12-30) + +1. Fix pose msg conversion when msg is missing orientation + * [Pull Request 450](https://github.com/ignitionrobotics/ign-gazebo/pull/450) + +1. Address code checker warnings + * [Pull Request 443](https://github.com/ignitionrobotics/ign-gazebo/pull/443) + * [Pull Request 491](https://github.com/ignitionrobotics/ign-gazebo/pull/491) + * [Pull Request 499](https://github.com/ignitionrobotics/ign-gazebo/pull/499) + * [Pull Request 502](https://github.com/ignitionrobotics/ign-gazebo/pull/502) + +1. Test fixes + * [Pull Request 455](https://github.com/ignitionrobotics/ign-gazebo/pull/455) + * [Pull Request 463](https://github.com/ignitionrobotics/ign-gazebo/pull/463) + * [Pull Request 452](https://github.com/ignitionrobotics/ign-gazebo/pull/452) + * [Pull Request 480](https://github.com/ignitionrobotics/ign-gazebo/pull/480) + +1. Documentation updates + * [Pull Request 472](https://github.com/ignitionrobotics/ign-gazebo/pull/472) + +1. Fix segfault in the Breadcrumb system when associated model is unloaded + * [Pull Request 454](https://github.com/ignitionrobotics/ign-gazebo/pull/454) + +1. Added user commands to example thermal camera world + * [Pull Request 442](https://github.com/ignitionrobotics/ign-gazebo/pull/442) + +1. Helper function to set component data + * [Pull Request 436](https://github.com/ignitionrobotics/ign-gazebo/pull/436) + +1. Remove unneeded if statement in EntityComponentManager + * [Pull Request 432](https://github.com/ignitionrobotics/ign-gazebo/pull/432) + +1. Clarify how time is represented in each phase of a System step + * [Pull Request 467](https://github.com/ignitionrobotics/ign-gazebo/pull/467) + +1. Switch to async state service request + * [Pull Request 461](https://github.com/ignitionrobotics/ign-gazebo/pull/461) + +1. Update key event handling + * [Pull Request 466](https://github.com/ignitionrobotics/ign-gazebo/pull/466) + +1. Tape Measure Plugin + * [Pull Request 456](https://github.com/ignitionrobotics/ign-gazebo/pull/456) + +1. Move deselect and preview termination to render thread + * [Pull Request 493](https://github.com/ignitionrobotics/ign-gazebo/pull/493) + +1. Logical audio sensor plugin + * [Pull Request 401](https://github.com/ignitionrobotics/ign-gazebo/pull/401) + +1. add frame_id and child_frame_id attribute support for DiffDrive + * [Pull Request 361](https://github.com/ignitionrobotics/ign-gazebo/pull/361) + +1. Add ability to record video based on sim time + * [Pull Request 414](https://github.com/ignitionrobotics/ign-gazebo/pull/414) + +1. Add lockstep mode to video recording + * [Pull Request 419](https://github.com/ignitionrobotics/ign-gazebo/pull/419) + +1. Disable right click menu when using measuring tool + * [Pull Request 458](https://github.com/ignitionrobotics/ign-gazebo/pull/458) + ### Ignition Gazebo 3.5.0 (2020-11-03) 1. Updated source build instructions From 88481d205dd193d05f58210a905fdc15a0d5d68e Mon Sep 17 00:00:00 2001 From: Steve Peters Date: Mon, 4 Jan 2021 09:28:49 -0800 Subject: [PATCH 07/21] Don't make docs on macOS (#528) add comment about doxygen bug Signed-off-by: Louise Poubel Signed-off-by: Steve Peters Co-authored-by: Louise Poubel --- CMakeLists.txt | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a21de380bc..2927065688 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,19 +158,24 @@ ign_create_packages() configure_file(${CMAKE_SOURCE_DIR}/api.md.in ${CMAKE_BINARY_DIR}/api.md) configure_file(${CMAKE_SOURCE_DIR}/tutorials.md.in ${CMAKE_BINARY_DIR}/tutorials.md) -ign_create_docs( - API_MAINPAGE_MD "${CMAKE_BINARY_DIR}/api.md" - TUTORIALS_MAINPAGE_MD "${CMAKE_BINARY_DIR}/tutorials.md" - ADDITIONAL_INPUT_DIRS "${CMAKE_SOURCE_DIR}/src/systems ${CMAKE_SOURCE_DIR}/src/gui/plugins" - TAGFILES - "${IGNITION-MATH_DOXYGEN_TAGFILE} = ${IGNITION-MATH_API_URL}" - "${IGNITION-MSGS_DOXYGEN_TAGFILE} = ${IGNITION-MSGS_API_URL}" - "${IGNITION-PHYSICS_DOXYGEN_TAGFILE} = ${IGNITION-PHYSICS_API_URL}" - "${IGNITION-PLUGIN_DOXYGEN_TAGFILE} = ${IGNITION-PLUGIN_API_URL}" - "${IGNITION-TRANSPORT_DOXYGEN_TAGFILE} = ${IGNITION-TRANSPORT_API_URL}" - "${IGNITION-SENSORS_DOXYGEN_TAGFILE} = ${IGNITION-SENSORS_API_URL}" - "${IGNITION-COMMON_DOXYGEN_TAGFILE} = ${IGNITION-COMMON_API_URL}" -) +# disable doxygen on macOS due to issues with doxygen 1.9.0 +# there is an unreleased fix; revert this when 1.9.1 is released +# https://github.com/ignitionrobotics/ign-gazebo/issues/520 +if (NOT APPLE) + ign_create_docs( + API_MAINPAGE_MD "${CMAKE_BINARY_DIR}/api.md" + TUTORIALS_MAINPAGE_MD "${CMAKE_BINARY_DIR}/tutorials.md" + ADDITIONAL_INPUT_DIRS "${CMAKE_SOURCE_DIR}/src/systems ${CMAKE_SOURCE_DIR}/src/gui/plugins" + TAGFILES + "${IGNITION-MATH_DOXYGEN_TAGFILE} = ${IGNITION-MATH_API_URL}" + "${IGNITION-MSGS_DOXYGEN_TAGFILE} = ${IGNITION-MSGS_API_URL}" + "${IGNITION-PHYSICS_DOXYGEN_TAGFILE} = ${IGNITION-PHYSICS_API_URL}" + "${IGNITION-PLUGIN_DOXYGEN_TAGFILE} = ${IGNITION-PLUGIN_API_URL}" + "${IGNITION-TRANSPORT_DOXYGEN_TAGFILE} = ${IGNITION-TRANSPORT_API_URL}" + "${IGNITION-SENSORS_DOXYGEN_TAGFILE} = ${IGNITION-SENSORS_API_URL}" + "${IGNITION-COMMON_DOXYGEN_TAGFILE} = ${IGNITION-COMMON_API_URL}" + ) +endif() if(TARGET doc) file(COPY ${CMAKE_SOURCE_DIR}/tutorials/files/ DESTINATION ${CMAKE_BINARY_DIR}/doxygen/html/files/) From 1655d47fbcfadac632be5a28a37472c41060b4f1 Mon Sep 17 00:00:00 2001 From: Louise Poubel Date: Mon, 4 Jan 2021 15:47:03 -0800 Subject: [PATCH 08/21] Updates to ardupilot migration tutorial (#525) Signed-off-by: Louise Poubel --- tutorials/migrating_ardupilot_plugin.md | 110 ++++++------------------ 1 file changed, 26 insertions(+), 84 deletions(-) diff --git a/tutorials/migrating_ardupilot_plugin.md b/tutorials/migrating_ardupilot_plugin.md index a7f65482f4..afdb36ae77 100644 --- a/tutorials/migrating_ardupilot_plugin.md +++ b/tutorials/migrating_ardupilot_plugin.md @@ -1,17 +1,15 @@ \page ardupilot -[TOC] +# Case study: migrating the ArduPilot ModelPlugin from Gazebo classic to Ignition Gazebo -# Case study: migrating the ArduPilot ModelPlugin from Classic Gazebo to Ignition Gazebo - -A variety of changes are required when migrating a plugin from Gazebo Classic -("Gazebo") to Ignition Gazebo ("Ignition"). In this tutorial we offer as a case +A variety of changes are required when migrating a plugin from Gazebo classic +to Ignition Gazebo. In this tutorial we offer as a case study the migration of one particular `ModelPlugin`, [ardupilot_gazebo](https://github.com/khancyr/ardupilot_gazebo). We hope that this example provides useful tips to others who are migrating their existing -plugins from Gazebo to Ignition. +plugins from classic to Ignition. -The complete, migrated version of the `ardupilot_gazebo` plugin covered in this tutorial +The complete, migrated version of the `ardupilot_gazebo` plugin covered in this tutorial can be found in [this fork](https://github.com/gerkey/ardupilot_gazebo/tree/ignition). ## Background @@ -24,7 +22,7 @@ documentation](https://ardupilot.org/dev/docs/using-gazebo-simulator-with-sitl.h As context to understand what we're migrating, here's a system diagram for how the ArduPilot Gazebo plugin works is used: - + *UAV icon credit: By Julian Herzog, CC BY 4.0, https://commons.wikimedia.org/w/index.php?curid=60965475* @@ -47,9 +45,9 @@ preserving the rest of the setup. Migration of this plugin involves modifications to multiple parts of the associated code: 1. The plugin header file, `ArduPilotPlugin.hh` -1. The plugin source file, `ArduPilotPlugin.cc` -1. The plugin's CMake build recipe, `CMakeLists.txt` -1. The custom model in which the plugin is used +2. The plugin source file, `ArduPilotPlugin.cc` +3. The plugin's CMake build recipe, `CMakeLists.txt` +4. The custom model in which the plugin is used We'll take them each in turn in the following sections. @@ -57,7 +55,7 @@ We'll take them each in turn in the following sections. ### Headers -The old code includes these Gazebo-related headers: +The old code includes these Gazebo classic headers: ```cpp // OLD @@ -67,7 +65,7 @@ The old code includes these Gazebo-related headers: ``` In the new code, we still need ``, because the underlying [SDFormat -library](http://sdformat.org/) is used by both Gazebo and Ignition. But in place of the `` headers, we'll pull in one from Ignition: +library](http://sdformat.org/) is used by both classic and Ignition. But in place of the `` headers, we'll pull in one from Ignition: ```cpp // NEW @@ -226,10 +224,10 @@ To better understand the ECS pattern as it is used in Ignition, it's helpful to learn about the EntityComponentManager (ECM), which is responsible for managing the ECS graph. A great resource to understand the logic under the hood of the ECM is the `SdfEntityCreator` class -([header](https://github.com/ignitionrobotics/ign-gazebo/blob/master/include/ignition/gazebo/SdfEntityCreator.hh), -[source](https://github.com/ignitionrobotics/ign-gazebo/blob/master/src/SdfEntityCreator.cc)). +([header](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo3/include/ignition/gazebo/SdfEntityCreator.hh), +[source](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo3/src/SdfEntityCreator.cc)). This class is responsible for mapping the content of an SDF file to the -entities and components that form the graph handled by the ECM. For example, If +entities and components that form the graph handled by the ECM. For example, if you wonder which components can be accessed by default from the plugin, this class is the best entry point. @@ -406,9 +404,6 @@ ignwarn << ... ; ignerr << ... ; ``` -**Suggestion**: Perhaps the old versions could stick around and be deprecated -instead of removed? - ### Plugin interface: Configure() Recall that `Configure()` replaces `Load()`. @@ -434,7 +429,7 @@ Also in the new code we need to make sure of the existence of the specific *components* that we need. In our case, we're going to access the `WorldPose` and `WorldLinearVelocity` components of the *entity* representing one of the UAV model's links. The data in those components will be periodically updated by -the physics *system* (I think). But the physics system will not necessarily +the physics *system*. But the physics system will not necessarily create the components, so before accessing them later in our code, we need to ensure that the components exist: @@ -453,13 +448,6 @@ if(!_ecm.EntityHasComponentType(this->dataPtr->modelLink, components::WorldLinea We'll see this pattern elsewhere in the new code: check for a component's existence, create it if necessary, then proceed with using it. -**Suggestion**: Perhaps we could add syntactic sugar to encapsulate the -check-and-create-if-necessary step? Or alternatively could we guarantee at -startup that systems create all of the components they can use? Either way it -would also be helpful to document which *components* a given *system* will read -from and write to, as they represent the system's API. As present it's easy for -a user to create and interact with a component that no system actually uses. - We also clone the `const sdf::Element` that we've passed so that we can call non-`const` methods on it: @@ -500,10 +488,6 @@ param = controlSDF->Get("vel_i_gain", control.pid.IGain()).first; param = controlSDF->Get("vel_d_gain", control.pid.DGain()).first; ``` -**Suggestion**: Perhaps the old methods could stick around and be deprecated -instead of removed? - - The old code does a bunch of lookups to get a pointer to the IMU sensor. In the new code, we just store the name of the sensors from the user-supplied SDF configuration: @@ -585,9 +569,6 @@ Though it's not part of the regular update loop, we subscribe to the IMU sensor data in `PreUpdate()` because the information that we need for that subscription isn't available when we're in `Configure()`. -**Suggestion**: Perhaps it should be possible to compute topics names for -subscription inside `Configure()`? - That one-time subscription logic looks like this, starting with determination of the right topic name and ending with registering our previously defined `imuCb()` method as the callback to receive new IMU data: @@ -598,34 +579,12 @@ if(!this->dataPtr->imuInitialized) { // Set unconditionally because we're only going to try this once. this->dataPtr->imuInitialized = true; - std::string imuTopicName; - _ecm.Each( - [&](const ignition::gazebo::Entity &_imu_entity, - const ignition::gazebo::components::Imu * /*_imu*/, - const ignition::gazebo::components::Name *_name)->bool - { - if(_name->Data() == this->dataPtr->imuName) - { - // The parent of the imu is imu_link - ignition::gazebo::Entity parent = _ecm.ParentEntity(_imu_entity); - this->dataPtr->modelLink = parent; - if(parent != ignition::gazebo::kNullEntity) - { - // The grandparent of the imu is the quad itself, which is where this plugin is attached - ignition::gazebo::Entity gparent = _ecm.ParentEntity(parent); - if(gparent != ignition::gazebo::kNullEntity) - { - ignition::gazebo::Model gparent_model(gparent); - if(gparent_model.Name(_ecm) == this->dataPtr->modelName) - { - imuTopicName = ignition::gazebo::scopedName(_imu_entity, _ecm) + "/imu"; - igndbg << "Computed IMU topic to be: " << imuTopicName << std::endl; - } - } - } - } - return true; - }); + + auto imuEntity = _ecm.EntityByComponents( + components::Name(this->dataPtr->imuName), + components::Imu(), + components::ParentEntity(this->dataPtr->modelLink)); + auto imuTopicName = _ecm.ComponentData(imuEntity); if(imuTopicName.empty()) { @@ -639,9 +598,6 @@ if(!this->dataPtr->imuInitialized) } ``` -**Suggestion**: There should be an easier way to compute the name of the topic -on which a given sensor's data will be published. - ### Writing to simulation Based on commands received from ArduPilot, new forces are applied to the @@ -663,19 +619,11 @@ exist): ```cpp // NEW -ignition::gazebo::components::JointForceCmd* jfcComp = - _ecm.Component(this->dataPtr->controls[i].joint); -if (jfcComp == nullptr) -{ - jfcComp = _ecm.Component( - _ecm.CreateComponent(this->dataPtr->controls[i].joint, - ignition::gazebo::components::JointForceCmd({0}))); -} -ignition::gazebo::components::JointVelocity* vComp = - _ecm.Component(this->dataPtr->controls[i].joint); -const double vel = vComp->Data()[0]; +const double vel = _ecm.ComponentData( + this->dataPtr->controls[i].joint); // ...do some feedback control math to compute force from vel... -jfcComp->Data()[0] = force; +_ecm.SetComponentData(this->dataPtr->controls[i].joint, + ignition::gazebo::components::JointForceCmd({force})); ``` A similar pattern is used for the case of setting a velocity on a joint; @@ -805,11 +753,9 @@ In the new code we explicitly reference each Ignition package that we use: # NEW find_package(sdformat9 REQUIRED) find_package(ignition-common3-all REQUIRED) -find_package(ignition-gazebo3-all REQUIRED) +find_package(ignition-gazebo3-all REQUIRED VERSION 3.6) find_package(ignition-math6-all REQUIRED) find_package(ignition-msgs5-all REQUIRED) -find_package(ignition-physics2-all REQUIRED) -find_package(ignition-sensors3-all REQUIRED) find_package(ignition-transport8-all REQUIRED) ``` @@ -837,8 +783,6 @@ include_directories( ${IGNITION-GAZEBO_INCLUDE_DIRS} ${IGNITION-MATH_INCLUDE_DIRS} ${IGNITION-MSGS_INCLUDE_DIRS} - ${IGNITION-PHYSICS_INCLUDE_DIRS} - ${IGNITION-SENSORS_INCLUDE_DIRS} ${IGNITION-TRANSPORT_INCLUDE_DIRS} ) @@ -848,8 +792,6 @@ link_libraries( ${IGNITION-GAZEBO_LIBRARIES} ${IGNITION-MATH_LIBRARIES} ${IGNITION-MSGS_LIBRARIES} - ${IGNITION-PHYSICS_LIBRARIES} - ${IGNITION-SENSORS_LIBRARIES} ${IGNITION-TRANSPORT_LIBRARIES} ) ``` From 9c0a0ab5d0969d83a68e0038172aaa22025289d2 Mon Sep 17 00:00:00 2001 From: Jose Luis Rivero Date: Tue, 5 Jan 2021 01:19:52 +0100 Subject: [PATCH 09/21] Update gtest to 1.10.0 for Windows compilation (ign-gazebo3) (#506) * Compile new gtest with c++11 * Use INSTANTIATE_TEST_SUITE_P instead of deprecated -INSTANTIATE_TEST_CASE_P Signed-off-by: Jose Luis Rivero --- src/EntityComponentManager_TEST.cc | 2 +- src/Server_TEST.cc | 2 +- src/SimulationRunner_TEST.cc | 2 +- test/CMakeLists.txt | 1 + test/gtest/cmake/Config.cmake.in | 9 + test/gtest/cmake/gtest.pc.in | 10 + test/gtest/cmake/gtest_main.pc.in | 11 + test/gtest/cmake/internal_utils.cmake | 197 +- test/gtest/cmake/libgtest.la.in | 21 + test/gtest/gtest-1.10.0.diff | 15 + test/gtest/gtest-1.7.0.diff | 44 - test/gtest/include/gtest/gtest-death-test.h | 71 +- test/gtest/include/gtest/gtest-matchers.h | 750 ++++ test/gtest/include/gtest/gtest-message.h | 56 +- test/gtest/include/gtest/gtest-param-test.h | 1208 +------ .../include/gtest/gtest-param-test.h.pump | 64 +- test/gtest/include/gtest/gtest-printers.h | 536 +-- test/gtest/include/gtest/gtest-spi.h | 20 +- test/gtest/include/gtest/gtest-test-part.h | 43 +- test/gtest/include/gtest/gtest-typed-test.h | 252 +- test/gtest/include/gtest/gtest.h | 1191 ++++--- test/gtest/include/gtest/gtest_pred_impl.h | 81 +- test/gtest/include/gtest/gtest_prod.h | 17 +- .../include/gtest/internal/custom/README.md | 56 + .../gtest/internal/custom/gtest-port.h | 37 + .../gtest/internal/custom/gtest-printers.h | 42 + .../include/gtest/internal/custom/gtest.h | 37 + .../internal/gtest-death-test-internal.h | 175 +- .../include/gtest/internal/gtest-filepath.h | 13 +- .../include/gtest/internal/gtest-internal.h | 842 +++-- .../include/gtest/internal/gtest-linked_ptr.h | 14 +- .../internal/gtest-param-util-generated.h | 158 +- .../gtest-param-util-generated.h.pump | 42 +- .../include/gtest/internal/gtest-param-util.h | 584 ++- .../include/gtest/internal/gtest-port-arch.h | 107 + .../gtest/include/gtest/internal/gtest-port.h | 1557 ++++---- .../include/gtest/internal/gtest-string.h | 30 +- .../include/gtest/internal/gtest-tuple.h | 8 + .../include/gtest/internal/gtest-tuple.h.pump | 8 + .../include/gtest/internal/gtest-type-util.h | 42 +- .../gtest/internal/gtest-type-util.h.pump | 43 +- test/gtest/src/gtest-all.cc | 6 +- test/gtest/src/gtest-death-test.cc | 601 +++- test/gtest/src/gtest-filepath.cc | 47 +- test/gtest/src/gtest-internal-inl.h | 339 +- test/gtest/src/gtest-matchers.cc | 97 + test/gtest/src/gtest-port.cc | 844 ++++- test/gtest/src/gtest-printers.cc | 131 +- test/gtest/src/gtest-test-part.cc | 34 +- test/gtest/src/gtest-typed-test.cc | 48 +- test/gtest/src/gtest.cc | 3139 +++++++++++------ test/gtest/src/gtest_main.cc | 17 +- test/integration/diff_drive_system.cc | 2 +- test/integration/examples_build.cc | 2 +- test/integration/scene_broadcaster_system.cc | 2 +- test/integration/velocity_control_system.cc | 2 +- 56 files changed, 8683 insertions(+), 5026 deletions(-) create mode 100644 test/gtest/cmake/Config.cmake.in create mode 100644 test/gtest/cmake/gtest.pc.in create mode 100644 test/gtest/cmake/gtest_main.pc.in create mode 100644 test/gtest/cmake/libgtest.la.in create mode 100644 test/gtest/gtest-1.10.0.diff delete mode 100644 test/gtest/gtest-1.7.0.diff create mode 100644 test/gtest/include/gtest/gtest-matchers.h create mode 100644 test/gtest/include/gtest/internal/custom/README.md create mode 100644 test/gtest/include/gtest/internal/custom/gtest-port.h create mode 100644 test/gtest/include/gtest/internal/custom/gtest-printers.h create mode 100644 test/gtest/include/gtest/internal/custom/gtest.h create mode 100644 test/gtest/include/gtest/internal/gtest-port-arch.h create mode 100644 test/gtest/src/gtest-matchers.cc diff --git a/src/EntityComponentManager_TEST.cc b/src/EntityComponentManager_TEST.cc index 6a9714d5c4..a58a056e63 100644 --- a/src/EntityComponentManager_TEST.cc +++ b/src/EntityComponentManager_TEST.cc @@ -2137,5 +2137,5 @@ TEST_P(EntityComponentManagerFixture, SetEntityCreateOffset) // Run multiple times. We want to make sure that static globals don't cause // problems. -INSTANTIATE_TEST_CASE_P(EntityComponentManagerRepeat, +INSTANTIATE_TEST_SUITE_P(EntityComponentManagerRepeat, EntityComponentManagerFixture, ::testing::Range(1, 10)); diff --git a/src/Server_TEST.cc b/src/Server_TEST.cc index 890604723a..b057678e28 100644 --- a/src/Server_TEST.cc +++ b/src/Server_TEST.cc @@ -996,4 +996,4 @@ TEST_P(ServerFixture, AddResourcePaths) // Run multiple times. We want to make sure that static globals don't cause // problems. -INSTANTIATE_TEST_CASE_P(ServerRepeat, ServerFixture, ::testing::Range(1, 2)); +INSTANTIATE_TEST_SUITE_P(ServerRepeat, ServerFixture, ::testing::Range(1, 2)); diff --git a/src/SimulationRunner_TEST.cc b/src/SimulationRunner_TEST.cc index 317d00aa9e..52795298b0 100644 --- a/src/SimulationRunner_TEST.cc +++ b/src/SimulationRunner_TEST.cc @@ -1294,5 +1294,5 @@ TEST_P(SimulationRunnerTest, GenerateWorldSdf) // Run multiple times. We want to make sure that static globals don't cause // problems. -INSTANTIATE_TEST_CASE_P(ServerRepeat, SimulationRunnerTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, SimulationRunnerTest, ::testing::Range(1, 2)); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c506039bc6..86cdb3578d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,6 +11,7 @@ configure_file (test_config.hh.in ${PROJECT_BINARY_DIR}/include/ignition/gazebo/ add_library(gtest STATIC gtest/src/gtest-all.cc) add_library(gtest_main STATIC gtest/src/gtest_main.cc) target_link_libraries(gtest_main gtest) +target_compile_features(gtest PUBLIC cxx_std_11) set(GTEST_LIBRARY "${PROJECT_BINARY_DIR}/test/libgtest.a") set(GTEST_MAIN_LIBRARY "${PROJECT_BINARY_DIR}/test/libgtest_main.a") diff --git a/test/gtest/cmake/Config.cmake.in b/test/gtest/cmake/Config.cmake.in new file mode 100644 index 0000000000..12be4498b1 --- /dev/null +++ b/test/gtest/cmake/Config.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ +include(CMakeFindDependencyMacro) +if (@GTEST_HAS_PTHREAD@) + set(THREADS_PREFER_PTHREAD_FLAG @THREADS_PREFER_PTHREAD_FLAG@) + find_dependency(Threads) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") +check_required_components("@project_name@") diff --git a/test/gtest/cmake/gtest.pc.in b/test/gtest/cmake/gtest.pc.in new file mode 100644 index 0000000000..9aae29e267 --- /dev/null +++ b/test/gtest/cmake/gtest.pc.in @@ -0,0 +1,10 @@ +prefix=${pcfiledir}/../.. +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: gtest +Description: GoogleTest (without main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Libs: -L${libdir} -lgtest @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ @CMAKE_THREAD_LIBS_INIT@ diff --git a/test/gtest/cmake/gtest_main.pc.in b/test/gtest/cmake/gtest_main.pc.in new file mode 100644 index 0000000000..915f2973af --- /dev/null +++ b/test/gtest/cmake/gtest_main.pc.in @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: gtest_main +Description: GoogleTest (with main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Requires: gtest +Libs: -L${libdir} -lgtest_main @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ @CMAKE_THREAD_LIBS_INIT@ diff --git a/test/gtest/cmake/internal_utils.cmake b/test/gtest/cmake/internal_utils.cmake index 8cb21894ce..2f70f0b084 100644 --- a/test/gtest/cmake/internal_utils.cmake +++ b/test/gtest/cmake/internal_utils.cmake @@ -12,6 +12,10 @@ # Test and Google Mock's option() definitions, and thus must be # called *after* the options have been defined. +if (POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +endif (POLICY CMP0054) + # Tweaks CMake's default compiler/linker settings to suit Google Test's needs. # # This must be a macro(), as inside a function string() can only @@ -20,8 +24,10 @@ macro(fix_default_compiler_settings_) if (MSVC) # For MSVC, CMake sets certain flags to defaults we want to override. # This replacement code is taken from sample in the CMake Wiki at - # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace. + # https://gitlab.kitware.com/cmake/community/wikis/FAQ#dynamic-replace. foreach (flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt) @@ -37,7 +43,12 @@ macro(fix_default_compiler_settings_) # We prefer more strict warning checking for building Google Test. # Replaces /W3 with /W4 in defaults. - string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}") + string(REPLACE "/W3" "/W4" ${flag_var} "${${flag_var}}") + + # Prevent D9025 warning for targets that have exception handling + # turned off (/EHs-c- flag). Where required, exceptions are explicitly + # re-enabled using the cxx_exception_flags variable. + string(REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}") endforeach() endif() endmacro() @@ -46,33 +57,41 @@ endmacro() # Google Mock. You can tweak these definitions to suit your need. A # variable's value is empty before it's explicitly assigned to. macro(config_compiler_and_linker) - if (NOT gtest_disable_pthreads) + # Note: pthreads on MinGW is not supported, even if available + # instead, we use windows threading primitives + unset(GTEST_HAS_PTHREAD) + if (NOT gtest_disable_pthreads AND NOT MINGW) # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. find_package(Threads) + if (CMAKE_USE_PTHREADS_INIT) + set(GTEST_HAS_PTHREAD ON) + endif() endif() fix_default_compiler_settings_() if (MSVC) # Newlines inside flags variables break CMake's NMake generator. # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. - set(cxx_base_flags "-GS -W4 -WX -wd4127 -wd4251 -wd4275 -nologo -J -Zi") - if (MSVC_VERSION LESS 1400) - # Suppress spurious warnings MSVC 7.1 sometimes issues. - # Forcing value to bool. - set(cxx_base_flags "${cxx_base_flags} -wd4800") - # Copy constructor and assignment operator could not be generated. - set(cxx_base_flags "${cxx_base_flags} -wd4511 -wd4512") - # Compatibility warnings not applicable to Google Test. - # Resolved overload was found by argument-dependent lookup. - set(cxx_base_flags "${cxx_base_flags} -wd4675") - endif() + set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J -Zi") set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32") set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN") set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") - set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0") + set(cxx_no_exception_flags "-EHs-c- -D_HAS_EXCEPTIONS=0") set(cxx_no_rtti_flags "-GR-") + # Suppress "unreachable code" warning + # http://stackoverflow.com/questions/3232669 explains the issue. + set(cxx_base_flags "${cxx_base_flags} -wd4702") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(cxx_base_flags "-Wall -Wshadow -Werror -Wconversion") + set(cxx_exception_flags "-fexceptions") + set(cxx_no_exception_flags "-fno-exceptions") + set(cxx_strict_flags "-W -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wunused-parameter -Wcast-align -Wchar-subscripts -Winline -Wredundant-decls") + set(cxx_no_rtti_flags "-fno-rtti") elseif (CMAKE_COMPILER_IS_GNUCXX) - set(cxx_base_flags "-Wall -Wshadow") + set(cxx_base_flags "-Wall -Wshadow -Werror") + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0) + set(cxx_base_flags "${cxx_base_flags} -Wno-error=dangling-else") + endif() set(cxx_exception_flags "-fexceptions") set(cxx_no_exception_flags "-fno-exceptions") # Until version 4.3.2, GCC doesn't define a macro to indicate @@ -104,19 +123,20 @@ macro(config_compiler_and_linker) set(cxx_no_rtti_flags "") endif() - if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed. - set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") + # The pthreads library is available and allowed? + if (DEFINED GTEST_HAS_PTHREAD) + set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=1") else() - set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0") + set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=0") endif() + set(cxx_base_flags "${cxx_base_flags} ${GTEST_HAS_PTHREAD_MACRO}") # For building gtest's own tests and samples. - set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}") + set(cxx_exception "${cxx_base_flags} ${cxx_exception_flags}") set(cxx_no_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}") set(cxx_default "${cxx_exception}") set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}") - set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1") # For building the gtest libraries. set(cxx_strict "${cxx_default} ${cxx_strict_flags}") @@ -131,13 +151,42 @@ function(cxx_library_with_type name type cxx_flags) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") + # Generate debug library name with a postfix. + set_target_properties(${name} + PROPERTIES + DEBUG_POSTFIX "d") + # Set the output directory for build artifacts + set_target_properties(${name} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + # make PDBs match library name + get_target_property(pdb_debug_postfix ${name} DEBUG_POSTFIX) + set_target_properties(${name} + PROPERTIES + PDB_NAME "${name}" + PDB_NAME_DEBUG "${name}${pdb_debug_postfix}" + COMPILE_PDB_NAME "${name}" + COMPILE_PDB_NAME_DEBUG "${name}${pdb_debug_postfix}") + if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") set_target_properties(${name} PROPERTIES COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") + if (NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + target_compile_definitions(${name} INTERFACE + $) + endif() endif() - if (CMAKE_USE_PTHREADS_INIT) - target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) + if (DEFINED GTEST_HAS_PTHREAD) + if ("${CMAKE_VERSION}" VERSION_LESS "3.1.0") + set(threads_spec ${CMAKE_THREAD_LIBS_INIT}) + else() + set(threads_spec Threads::Threads) + endif() + target_link_libraries(${name} PUBLIC ${threads_spec}) endif() endfunction() @@ -159,6 +208,10 @@ endfunction() # is built from the given source files with the given compiler flags. function(cxx_executable_with_flags name cxx_flags libs) add_executable(${name} ${ARGN}) + if (MSVC) + # BigObj required for tests. + set(cxx_flags "${cxx_flags} -bigobj") + endif() if (cxx_flags) set_target_properties(${name} PROPERTIES @@ -195,7 +248,13 @@ find_package(PythonInterp) # from the given source files with the given compiler flags. function(cxx_test_with_flags name cxx_flags libs) cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) - add_test(${name} ${name}) + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND "powershell" "-Command" "${CMAKE_CURRENT_BINARY_DIR}/$/RunTest.ps1" "$") + else() + add_test(NAME ${name} + COMMAND "$") + endif() endfunction() # cxx_test(name libs srcs...) @@ -213,15 +272,87 @@ endfunction() # creates a Python test with the given name whose main module is in # test/name.py. It does nothing if Python is not installed. function(py_test name) - # We are not supporting Python tests on Linux yet as they consider - # all Linux environments to be google3 and try to use google3 features. if (PYTHONINTERP_FOUND) - # ${CMAKE_BINARY_DIR} is known at configuration time, so we can - # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known - # only at ctest runtime (by calling ctest -c ), so - # we have to escape $ to delay variable substitution here. - add_test(${name} - ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py - --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE}) + if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 3.1) + if (CMAKE_CONFIGURATION_TYPES) + # Multi-configuration build generators as for Visual Studio save + # output in a subdirectory of CMAKE_CURRENT_BINARY_DIR (Debug, + # Release etc.), so we have to provide it here. + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND powershell -Command ${CMAKE_CURRENT_BINARY_DIR}/$/RunTest.ps1 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/$ ${ARGN}) + else() + add_test(NAME ${name} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/$ ${ARGN}) + endif() + else (CMAKE_CONFIGURATION_TYPES) + # Single-configuration build generators like Makefile generators + # don't have subdirs below CMAKE_CURRENT_BINARY_DIR. + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND powershell -Command ${CMAKE_CURRENT_BINARY_DIR}/RunTest.ps1 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR} ${ARGN}) + else() + add_test(NAME ${name} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR} ${ARGN}) + endif() + endif (CMAKE_CONFIGURATION_TYPES) + else() + # ${CMAKE_CURRENT_BINARY_DIR} is known at configuration time, so we can + # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known + # only at ctest runtime (by calling ctest -c ), so + # we have to escape $ to delay variable substitution here. + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND powershell -Command ${CMAKE_CURRENT_BINARY_DIR}/RunTest.ps1 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE} ${ARGN}) + else() + add_test(NAME ${name} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE} ${ARGN}) + endif() + endif() + endif(PYTHONINTERP_FOUND) +endfunction() + +# install_project(targets...) +# +# Installs the specified targets and configures the associated pkgconfig files. +function(install_project) + if(INSTALL_GTEST) + install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + # Install the project targets. + install(TARGETS ${ARGN} + EXPORT ${targets_export_name} + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + # Install PDBs + foreach(t ${ARGN}) + get_target_property(t_pdb_name ${t} COMPILE_PDB_NAME) + get_target_property(t_pdb_name_debug ${t} COMPILE_PDB_NAME_DEBUG) + get_target_property(t_pdb_output_directory ${t} PDB_OUTPUT_DIRECTORY) + install(FILES + "${t_pdb_output_directory}/\${CMAKE_INSTALL_CONFIG_NAME}/$<$:${t_pdb_name_debug}>$<$>:${t_pdb_name}>.pdb" + DESTINATION ${CMAKE_INSTALL_LIBDIR} + OPTIONAL) + endforeach() + endif() + # Configure and install pkgconfig files. + foreach(t ${ARGN}) + set(configured_pc "${generated_dir}/${t}.pc") + configure_file("${PROJECT_SOURCE_DIR}/cmake/${t}.pc.in" + "${configured_pc}" @ONLY) + install(FILES "${configured_pc}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + endforeach() endif() endfunction() diff --git a/test/gtest/cmake/libgtest.la.in b/test/gtest/cmake/libgtest.la.in new file mode 100644 index 0000000000..840c83885f --- /dev/null +++ b/test/gtest/cmake/libgtest.la.in @@ -0,0 +1,21 @@ +# libgtest.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.6 + +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Names of this library. +library_names='libgtest.so' + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='@CMAKE_INSTALL_FULL_LIBDIR@' diff --git a/test/gtest/gtest-1.10.0.diff b/test/gtest/gtest-1.10.0.diff new file mode 100644 index 0000000000..9df3ab2100 --- /dev/null +++ b/test/gtest/gtest-1.10.0.diff @@ -0,0 +1,15 @@ +diff --git a/test/gtest/src/gtest.cc b/test/gtest/src/gtest.cc +index a5b4e5a..1dff1a6 100644 +--- a/test/gtest/src/gtest.cc ++++ b/test/gtest/src/gtest.cc +@@ -34,6 +34,10 @@ + #include "gtest/internal/custom/gtest.h" + #include "gtest/gtest-spi.h" + ++#ifndef _WIN32 ++#pragma GCC system_header ++#endif ++ + #include + #include + #include diff --git a/test/gtest/gtest-1.7.0.diff b/test/gtest/gtest-1.7.0.diff deleted file mode 100644 index e8783960fc..0000000000 --- a/test/gtest/gtest-1.7.0.diff +++ /dev/null @@ -1,44 +0,0 @@ -diff -r a5e72dd0ecf3 test/gtest/include/gtest/gtest-typed-test.h ---- a/test/gtest/include/gtest/gtest-typed-test.h Mon Nov 04 11:47:43 2013 -0800 -+++ b/test/gtest/include/gtest/gtest-typed-test.h Mon Nov 04 11:49:12 2013 -0800 -@@ -31,6 +31,7 @@ - - #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ - #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ -+#pragma GCC system_header - - // This header implements typed tests and type-parameterized tests. - -diff -r a5e72dd0ecf3 test/gtest/src/gtest.cc ---- a/test/gtest/src/gtest.cc Mon Nov 04 11:47:43 2013 -0800 -+++ b/test/gtest/src/gtest.cc Mon Nov 04 11:49:12 2013 -0800 -@@ -33,6 +33,7 @@ - - #include "gtest/gtest.h" - #include "gtest/gtest-spi.h" -+#pragma GCC system_header - - #include - #include -diff -r c33b44f8a9a1 test/gtest/include/gtest/internal/gtest-port.h ---- a/test/gtest/include/gtest/internal/gtest-port.h Wed Nov 06 11:23:38 2013 -0800 -+++ b/test/gtest/include/gtest/internal/gtest-port.h Wed Nov 06 17:12:57 2013 -0800 -@@ -39,6 +39,7 @@ - - #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ - #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -+#pragma GCC system_header - - // The user can define the following macros in the build script to - // control Google Test's behavior. If the user doesn't define a macro -diff -r e980730656c1 test/gtest/include/gtest/gtest-printers.h ---- a/test/gtest/include/gtest/gtest-printers.h Wed Nov 06 17:13:57 2013 -0800 -+++ b/test/gtest/include/gtest/gtest-printers.h Thu Nov 07 09:29:28 2013 -0800 -@@ -94,6 +94,7 @@ - - #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ - #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ -+#pragma GCC system_header - - #include // NOLINT - #include diff --git a/test/gtest/include/gtest/gtest-death-test.h b/test/gtest/include/gtest/gtest-death-test.h index 957a69c6a9..dc878ffbb3 100644 --- a/test/gtest/include/gtest/gtest-death-test.h +++ b/test/gtest/include/gtest/gtest-death-test.h @@ -26,14 +26,14 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ @@ -99,10 +99,11 @@ GTEST_API_ bool InDeathTestChild(); // // On the regular expressions used in death tests: // +// GOOGLETEST_CM0005 DO NOT DELETE // On POSIX-compliant systems (*nix), we use the library, // which uses the POSIX extended regex syntax. // -// On other platforms (e.g. Windows), we only support a simple regex +// On other platforms (e.g. Windows or Mac), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE @@ -160,7 +161,6 @@ GTEST_API_ bool InDeathTestChild(); // is rarely a problem as people usually don't put the test binary // directory in PATH. // -// TODO(wan@google.com): make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output @@ -169,7 +169,7 @@ GTEST_API_ bool InDeathTestChild(); GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) // Like ASSERT_EXIT, but continues on to successive tests in the -// test case, if any: +// test suite, if any: # define EXPECT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) @@ -180,7 +180,7 @@ GTEST_API_ bool InDeathTestChild(); ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Like ASSERT_DEATH, but continues on to successive tests in the -// test case, if any: +// test suite, if any: # define EXPECT_DEATH(statement, regex) \ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) @@ -198,9 +198,10 @@ class GTEST_API_ ExitedWithCode { const int exit_code_; }; -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Tests that an exit code describes an exit due to termination by a // given signal. +// GOOGLETEST_CM0006 DO NOT DELETE class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); @@ -226,7 +227,7 @@ class GTEST_API_ KilledBySignal { // return 12; // } // -// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) { // int sideeffect = 0; // // Only asserts in dbg. // EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); @@ -272,6 +273,54 @@ class GTEST_API_ KilledBySignal { # endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters +// on systems that support death tests. This allows one to write such a macro on +// a system that does not support death tests and be sure that it will compile +// on a death-test supporting system. It is exposed publicly so that systems +// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST +// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and +// ASSERT_DEATH_IF_SUPPORTED. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter if and only if EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is @@ -284,9 +333,9 @@ class GTEST_API_ KilledBySignal { ASSERT_DEATH(statement, regex) #else # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return) #endif } // namespace testing diff --git a/test/gtest/include/gtest/gtest-matchers.h b/test/gtest/include/gtest/gtest-matchers.h new file mode 100644 index 0000000000..9de6c2e10a --- /dev/null +++ b/test/gtest/include/gtest/gtest-matchers.h @@ -0,0 +1,750 @@ +// Copyright 2007, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +// IWYU pragma: private, include "testing/base/public/gunit.h" +// IWYU pragma: friend third_party/googletest/googlemock/.* +// IWYU pragma: friend third_party/googletest/googletest/.* + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ + +#include +#include +#include +#include + +#include "gtest/gtest-printers.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +// MSVC warning C5046 is new as of VS2017 version 15.8. +#if defined(_MSC_VER) && _MSC_VER >= 1915 +#define GTEST_MAYBE_5046_ 5046 +#else +#define GTEST_MAYBE_5046_ +#endif + +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by + clients of class B */ + /* Symbol involving type with internal linkage not defined */) + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherImpl that implements the +// MatcherInterface interface, and +// 2. a factory function that creates a Matcher object from a +// FooMatcherImpl*. +// +// The two-level delegation design makes it possible to allow a user +// to write "v" instead of "Eq(v)" where a Matcher is expected, which +// is impossible if we pass matchers by pointers. It also eases +// ownership management as Matcher objects can now be copied like +// plain values. + +// MatchResultListener is an abstract class. Its << operator can be +// used by a matcher to explain why a value matches or doesn't match. +// +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream, and does not dereference it + // in the constructor or destructor. + explicit MatchResultListener(::std::ostream* os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x) { + if (stream_ != nullptr) *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream* stream() { return stream_; } + + // Returns true if and only if the listener is interested in an explanation + // of the match result. A matcher's MatchAndExplain() method can use + // this information to avoid generating the explanation when no one + // intends to hear it. + bool IsInterested() const { return stream_ != nullptr; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + +// An instance of a subclass of this knows how to describe itself as a +// matcher. +class MatcherDescriberInterface { + public: + virtual ~MatcherDescriberInterface() {} + + // Describes this matcher to an ostream. The function should print + // a verb phrase that describes the property a value matching this + // matcher should have. The subject of the verb phrase is the value + // being matched. For example, the DescribeTo() method of the Gt(7) + // matcher prints "is greater than 7". + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. For + // example, if the description of this matcher is "is greater than + // 7", the negated description could be "is not greater than 7". + // You are not required to override this when implementing + // MatcherInterface, but it is highly advised so that your matcher + // can produce good error messages. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; + } +}; + +// The implementation of a matcher. +template +class MatcherInterface : public MatcherDescriberInterface { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener' if necessary (see the next paragraph), in + // the form of a non-restrictive relative clause ("which ...", + // "whose ...", etc) that describes x. For example, the + // MatchAndExplain() method of the Pointee(...) matcher should + // generate an explanation like "which points to ...". + // + // Implementations of MatchAndExplain() should add an explanation of + // the match result *if and only if* they can provide additional + // information that's not already present (or not obvious) in the + // print-out of x and the matcher's description. Whether the match + // succeeds is not a factor in deciding whether an explanation is + // needed, as sometimes the caller needs to print a failure message + // when the match succeeds (e.g. when the matcher is used inside + // Not()). + // + // For example, a "has at least 10 elements" matcher should explain + // what the actual element count is, regardless of the match result, + // as it is useful information to the reader; on the other hand, an + // "is empty" matcher probably only needs to explain what the actual + // size is when the match fails, as it's redundant to say that the + // size is 0 when the value is already known to be empty. + // + // You should override this method when defining a new matcher. + // + // It's the responsibility of the caller (Google Test) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Inherits these methods from MatcherDescriberInterface: + // virtual void DescribeTo(::std::ostream* os) const = 0; + // virtual void DescribeNegationTo(::std::ostream* os) const; +}; + +namespace internal { + +// Converts a MatcherInterface to a MatcherInterface. +template +class MatcherInterfaceAdapter : public MatcherInterface { + public: + explicit MatcherInterfaceAdapter(const MatcherInterface* impl) + : impl_(impl) {} + ~MatcherInterfaceAdapter() override { delete impl_; } + + void DescribeTo(::std::ostream* os) const override { impl_->DescribeTo(os); } + + void DescribeNegationTo(::std::ostream* os) const override { + impl_->DescribeNegationTo(os); + } + + bool MatchAndExplain(const T& x, + MatchResultListener* listener) const override { + return impl_->MatchAndExplain(x, listener); + } + + private: + const MatcherInterface* const impl_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter); +}; + +struct AnyEq { + template + bool operator()(const A& a, const B& b) const { return a == b; } +}; +struct AnyNe { + template + bool operator()(const A& a, const B& b) const { return a != b; } +}; +struct AnyLt { + template + bool operator()(const A& a, const B& b) const { return a < b; } +}; +struct AnyGt { + template + bool operator()(const A& a, const B& b) const { return a > b; } +}; +struct AnyLe { + template + bool operator()(const A& a, const B& b) const { return a <= b; } +}; +struct AnyGe { + template + bool operator()(const A& a, const B& b) const { return a >= b; } +}; + +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(nullptr) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream* os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +// An internal class for implementing Matcher, which will derive +// from it. We put functionalities common to all Matcher +// specializations here to avoid code duplication. +template +class MatcherBase { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener'. + bool MatchAndExplain(const T& x, MatchResultListener* listener) const { + return impl_->MatchAndExplain(x, listener); + } + + // Returns true if and only if this matcher matches x. + bool Matches(const T& x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } + + // Describes this matcher to an ostream. + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the negation of this matcher to an ostream. + void DescribeNegationTo(::std::ostream* os) const { + impl_->DescribeNegationTo(os); + } + + // Explains why x matches, or doesn't match, the matcher. + void ExplainMatchResultTo(const T& x, ::std::ostream* os) const { + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); + } + + // Returns the describer for this matcher object; retains ownership + // of the describer, which is only guaranteed to be alive when + // this matcher object is alive. + const MatcherDescriberInterface* GetDescriber() const { + return impl_.get(); + } + + protected: + MatcherBase() {} + + // Constructs a matcher from its implementation. + explicit MatcherBase(const MatcherInterface* impl) : impl_(impl) {} + + template + explicit MatcherBase( + const MatcherInterface* impl, + typename std::enable_if::value>::type* = + nullptr) + : impl_(new internal::MatcherInterfaceAdapter(impl)) {} + + MatcherBase(const MatcherBase&) = default; + MatcherBase& operator=(const MatcherBase&) = default; + MatcherBase(MatcherBase&&) = default; + MatcherBase& operator=(MatcherBase&&) = default; + + virtual ~MatcherBase() {} + + private: + std::shared_ptr> impl_; +}; + +} // namespace internal + +// A Matcher is a copyable and IMMUTABLE (except by assignment) +// object that can check whether a value of type T matches. The +// implementation of Matcher is just a std::shared_ptr to const +// MatcherInterface. Don't inherit from Matcher! +template +class Matcher : public internal::MatcherBase { + public: + // Constructs a null matcher. Needed for storing Matcher objects in STL + // containers. A default-constructed matcher is not yet initialized. You + // cannot use it until a valid value has been assigned to it. + explicit Matcher() {} // NOLINT + + // Constructs a matcher from its implementation. + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template + explicit Matcher( + const MatcherInterface* impl, + typename std::enable_if::value>::type* = + nullptr) + : internal::MatcherBase(impl) {} + + // Implicit constructor here allows people to write + // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes + Matcher(T value); // NOLINT +}; + +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +#if GTEST_HAS_ABSL +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views directly. + Matcher(absl::string_view s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views directly. + Matcher(absl::string_view s); // NOLINT +}; +#endif // GTEST_HAS_ABSL + +// Prints a matcher in a human-readable format. +template +std::ostream& operator<<(std::ostream& os, const Matcher& matcher) { + matcher.DescribeTo(&os); + return os; +} + +// The PolymorphicMatcher class template makes it easy to implement a +// polymorphic matcher (i.e. a matcher that can match values of more +// than one type, e.g. Eq(n) and NotNull()). +// +// To define a polymorphic matcher, a user should provide an Impl +// class that has a DescribeTo() method and a DescribeNegationTo() +// method, and define a member function (or member function template) +// +// bool MatchAndExplain(const Value& value, +// MatchResultListener* listener) const; +// +// See the definition of NotNull() for a complete example. +template +class PolymorphicMatcher { + public: + explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} + + // Returns a mutable reference to the underlying matcher + // implementation object. + Impl& mutable_impl() { return impl_; } + + // Returns an immutable reference to the underlying matcher + // implementation object. + const Impl& impl() const { return impl_; } + + template + operator Matcher() const { + return Matcher(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public MatcherInterface { + public: + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); } + + virtual void DescribeNegationTo(::std::ostream* os) const { + impl_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_.MatchAndExplain(x, listener); + } + + private: + const Impl impl_; + }; + + Impl impl_; +}; + +// Creates a matcher from its implementation. +// DEPRECATED: Especially in the generic code, prefer: +// Matcher(new MyMatcherImpl(...)); +// +// MakeMatcher may create a Matcher that accepts its argument by value, which +// leads to unnecessary copies & lack of support for non-copyable types. +template +inline Matcher MakeMatcher(const MatcherInterface* impl) { + return Matcher(impl); +} + +// Creates a polymorphic matcher from its implementation. This is +// easier to use than the PolymorphicMatcher constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicMatcher(foo); +// vs +// PolymorphicMatcher(foo); +template +inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { + return PolymorphicMatcher(impl); +} + +namespace internal { +// Implements a matcher that compares a given value with a +// pre-supplied value using one of the ==, <=, <, etc, operators. The +// two values being compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq(5) can be +// used to match an int, a short, a double, etc). Therefore we use +// a template type conversion operator in the implementation. +// +// The following template definition assumes that the Rhs parameter is +// a "bare" type (i.e. neither 'const T' nor 'T&'). +template +class ComparisonBase { + public: + explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} + template + operator Matcher() const { + return Matcher(new Impl(rhs_)); + } + + private: + template + static const T& Unwrap(const T& v) { return v; } + template + static const T& Unwrap(std::reference_wrapper v) { return v; } + + template + class Impl : public MatcherInterface { + public: + explicit Impl(const Rhs& rhs) : rhs_(rhs) {} + bool MatchAndExplain(Lhs lhs, + MatchResultListener* /* listener */) const override { + return Op()(lhs, Unwrap(rhs_)); + } + void DescribeTo(::std::ostream* os) const override { + *os << D::Desc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + void DescribeNegationTo(::std::ostream* os) const override { + *os << D::NegatedDesc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + + private: + Rhs rhs_; + }; + Rhs rhs_; +}; + +template +class EqMatcher : public ComparisonBase, Rhs, AnyEq> { + public: + explicit EqMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyEq>(rhs) { } + static const char* Desc() { return "is equal to"; } + static const char* NegatedDesc() { return "isn't equal to"; } +}; +template +class NeMatcher : public ComparisonBase, Rhs, AnyNe> { + public: + explicit NeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyNe>(rhs) { } + static const char* Desc() { return "isn't equal to"; } + static const char* NegatedDesc() { return "is equal to"; } +}; +template +class LtMatcher : public ComparisonBase, Rhs, AnyLt> { + public: + explicit LtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLt>(rhs) { } + static const char* Desc() { return "is <"; } + static const char* NegatedDesc() { return "isn't <"; } +}; +template +class GtMatcher : public ComparisonBase, Rhs, AnyGt> { + public: + explicit GtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGt>(rhs) { } + static const char* Desc() { return "is >"; } + static const char* NegatedDesc() { return "isn't >"; } +}; +template +class LeMatcher : public ComparisonBase, Rhs, AnyLe> { + public: + explicit LeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLe>(rhs) { } + static const char* Desc() { return "is <="; } + static const char* NegatedDesc() { return "isn't <="; } +}; +template +class GeMatcher : public ComparisonBase, Rhs, AnyGe> { + public: + explicit GeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGe>(rhs) { } + static const char* Desc() { return "is >="; } + static const char* NegatedDesc() { return "isn't >="; } +}; + +// Implements polymorphic matchers MatchesRegex(regex) and +// ContainsRegex(regex), which can be used as a Matcher as long as +// T can be converted to a string. +class MatchesRegexMatcher { + public: + MatchesRegexMatcher(const RE* regex, bool full_match) + : regex_(regex), full_match_(full_match) {} + +#if GTEST_HAS_ABSL + bool MatchAndExplain(const absl::string_view& s, + MatchResultListener* listener) const { + return MatchAndExplain(std::string(s), listener); + } +#endif // GTEST_HAS_ABSL + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != nullptr && MatchAndExplain(std::string(s), listener); + } + + // Matches anything that can convert to std::string. + // + // This is a template, not just a plain function with const std::string&, + // because absl::string_view has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const std::string& s2(s); + return full_match_ ? RE::FullMatch(s2, *regex_) + : RE::PartialMatch(s2, *regex_); + } + + void DescribeTo(::std::ostream* os) const { + *os << (full_match_ ? "matches" : "contains") << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't " << (full_match_ ? "match" : "contain") + << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + private: + const std::shared_ptr regex_; + const bool full_match_; +}; +} // namespace internal + +// Matches a string that fully matches regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher MatchesRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); +} +inline PolymorphicMatcher MatchesRegex( + const std::string& regex) { + return MatchesRegex(new internal::RE(regex)); +} + +// Matches a string that contains regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher ContainsRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); +} +inline PolymorphicMatcher ContainsRegex( + const std::string& regex) { + return ContainsRegex(new internal::RE(regex)); +} + +// Creates a polymorphic matcher that matches anything equal to x. +// Note: if the parameter of Eq() were declared as const T&, Eq("foo") +// wouldn't compile. +template +inline internal::EqMatcher Eq(T x) { return internal::EqMatcher(x); } + +// Constructs a Matcher from a 'value' of type T. The constructed +// matcher matches any value that's equal to 'value'. +template +Matcher::Matcher(T value) { *this = Eq(value); } + +// Creates a monomorphic matcher that matches anything with type Lhs +// and equal to rhs. A user may need to use this instead of Eq(...) +// in order to resolve an overloading ambiguity. +// +// TypedEq(x) is just a convenient short-hand for Matcher(Eq(x)) +// or Matcher(x), but more readable than the latter. +// +// We could define similar monomorphic matchers for other comparison +// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do +// it yet as those are used much less than Eq() in practice. A user +// can always write Matcher(Lt(5)) to be explicit about the type, +// for example. +template +inline Matcher TypedEq(const Rhs& rhs) { return Eq(rhs); } + +// Creates a polymorphic matcher that matches anything >= x. +template +inline internal::GeMatcher Ge(Rhs x) { + return internal::GeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything > x. +template +inline internal::GtMatcher Gt(Rhs x) { + return internal::GtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything <= x. +template +inline internal::LeMatcher Le(Rhs x) { + return internal::LeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything < x. +template +inline internal::LtMatcher Lt(Rhs x) { + return internal::LtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything != x. +template +inline internal::NeMatcher Ne(Rhs x) { + return internal::NeMatcher(x); +} +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046 + +#endif // GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ diff --git a/test/gtest/include/gtest/gtest-message.h b/test/gtest/include/gtest/gtest-message.h index fe879bca79..4a80e11e6b 100644 --- a/test/gtest/include/gtest/gtest-message.h +++ b/test/gtest/include/gtest/gtest-message.h @@ -26,10 +26,9 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the Message class. // @@ -43,13 +42,19 @@ // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include +#include #include "gtest/internal/gtest-port.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. void operator<<(const testing::internal::Secret&, int); @@ -102,14 +107,6 @@ class GTEST_API_ Message { *ss_ << str; } -#if GTEST_OS_SYMBIAN - // Streams a value (either a pointer or not) to this object. - template - inline Message& operator <<(const T& value) { - StreamHelper(typename internal::is_pointer::type(), value); - return *this; - } -#else // Streams a non-pointer value to this object. template inline Message& operator <<(const T& val) { @@ -147,14 +144,13 @@ class GTEST_API_ Message { // as "(null)". template inline Message& operator <<(T* const& pointer) { // NOLINT - if (pointer == NULL) { + if (pointer == nullptr) { *ss_ << "(null)"; } else { *ss_ << pointer; } return *this; } -#endif // GTEST_OS_SYMBIAN // Since the basic IO manipulators are overloaded for both narrow // and wide streams, we have to provide this specialized definition @@ -183,12 +179,6 @@ class GTEST_API_ Message { Message& operator <<(const ::std::wstring& wstr); #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_GLOBAL_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::wstring& wstr); -#endif // GTEST_HAS_GLOBAL_WSTRING - // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". // @@ -196,32 +186,8 @@ class GTEST_API_ Message { std::string GetString() const; private: - -#if GTEST_OS_SYMBIAN - // These are needed as the Nokia Symbian Compiler cannot decide between - // const T& and const T* in a function template. The Nokia compiler _can_ - // decide between class template specializations for T and T*, so a - // tr1::type_traits-like is_pointer works, and we can overload on that. - template - inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - *ss_ << pointer; - } - } - template - inline void StreamHelper(internal::false_type /*is_pointer*/, - const T& value) { - // See the comments in Message& operator <<(const T&) above for why - // we need this using statement. - using ::operator <<; - *ss_ << value; - } -#endif // GTEST_OS_SYMBIAN - // We'll hold the text streamed to this object here. - const internal::scoped_ptr< ::std::stringstream> ss_; + const std::unique_ptr< ::std::stringstream> ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. @@ -247,4 +213,6 @@ std::string StreamableToString(const T& streamable) { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ diff --git a/test/gtest/include/gtest/gtest-param-test.h b/test/gtest/include/gtest/gtest-param-test.h index d6702c8f16..c2e6eae3d8 100644 --- a/test/gtest/include/gtest/gtest-param-test.h +++ b/test/gtest/include/gtest/gtest-param-test.h @@ -1,7 +1,3 @@ -// This file was GENERATED by command: -// pump.py gtest-param-test.h.pump -// DO NOT EDIT BY HAND!!! - // Copyright 2008, Google Inc. // All rights reserved. // @@ -31,13 +27,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: vladl@google.com (Vlad Losev) -// // Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) +// in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ @@ -76,10 +71,10 @@ TEST_P(FooTest, HasBlahBlah) { ... } -// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// Finally, you can use INSTANTIATE_TEST_SUITE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which +// (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // @@ -97,17 +92,17 @@ TEST_P(FooTest, HasBlahBlah) { // For more details, see comments at the definitions of these functions below // in this file. // -// The following statement will instantiate tests from the FooTest test case +// The following statement will instantiate tests from the FooTest test suite // each with parameter values "meeny", "miny", and "moe". -INSTANTIATE_TEST_CASE_P(InstantiationName, - FooTest, - Values("meeny", "miny", "moe")); +INSTANTIATE_TEST_SUITE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you -// can instantiate it more then once) the first argument to the -// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the -// actual test case name. Remember to pick unique prefixes for different +// can instantiate it more than once) the first argument to the +// INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the +// actual test suite name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // @@ -124,7 +119,7 @@ INSTANTIATE_TEST_CASE_P(InstantiationName, // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; -INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); +INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // @@ -133,9 +128,9 @@ INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // -// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests -// in the given test case, whether their definitions come before or -// AFTER the INSTANTIATE_TEST_CASE_P statement. +// Please note that INSTANTIATE_TEST_SUITE_P will instantiate all tests +// in the given test suite, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_SUITE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. @@ -179,31 +174,23 @@ TEST_P(DerivedTest, DoesBlah) { #endif // 0 -#include "gtest/internal/gtest-port.h" - -#if !GTEST_OS_SYMBIAN -# include -#endif +#include +#include -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" -#include "gtest/internal/gtest-param-util-generated.h" - -#if GTEST_HAS_PARAM_TEST +#include "gtest/internal/gtest-port.h" namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- -// parameterized tests. When a parameterized test case is instantiated +// parameterized tests. When a parameterized test suite is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // -// In the following sample, tests from test case FooTest are instantiated +// In the following sample, tests from test suite FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; @@ -212,7 +199,7 @@ namespace testing { // } // TEST_P(FooTest, TestThat) { // } -// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// INSTANTIATE_TEST_SUITE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. @@ -269,13 +256,13 @@ internal::ParamGenerator Range(T start, T end) { // // Examples: // -// This instantiates tests from test case StringTest +// This instantiates tests from test suite StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings)); // -// This instantiates tests from test case StlStringTest +// This instantiates tests from test suite StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { @@ -285,9 +272,9 @@ internal::ParamGenerator Range(T start, T end) { // return v; // } // -// INSTANTIATE_TEST_CASE_P(CharSequence, -// StlStringTest, -// ValuesIn(GetParameterStrings())); +// INSTANTIATE_TEST_SUITE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest @@ -300,16 +287,15 @@ internal::ParamGenerator Range(T start, T end) { // return list; // } // ::std::list l = GetParameterChars(); -// INSTANTIATE_TEST_CASE_P(CharSequence2, -// CharTest, -// ValuesIn(l.begin(), l.end())); +// INSTANTIATE_TEST_SUITE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> + typename std::iterator_traits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { - typedef typename ::testing::internal::IteratorTraits - ::value_type ParamType; + typedef typename std::iterator_traits::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } @@ -332,869 +318,22 @@ internal::ParamGenerator ValuesIn( // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // -// For example, this instantiates tests from test case BarTest each +// For example, this instantiates tests from test suite BarTest each // with values "one", "two", and "three": // -// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// INSTANTIATE_TEST_SUITE_P(NumSequence, +// BarTest, +// Values("one", "two", "three")); // -// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// This instantiates tests from test suite BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // -// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // -// Currently, Values() supports from 1 to 50 parameters. // -template -internal::ValueArray1 Values(T1 v1) { - return internal::ValueArray1(v1); -} - -template -internal::ValueArray2 Values(T1 v1, T2 v2) { - return internal::ValueArray2(v1, v2); -} - -template -internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { - return internal::ValueArray3(v1, v2, v3); -} - -template -internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { - return internal::ValueArray4(v1, v2, v3, v4); -} - -template -internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5) { - return internal::ValueArray5(v1, v2, v3, v4, v5); -} - -template -internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6) { - return internal::ValueArray6(v1, v2, v3, v4, v5, v6); -} - -template -internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7) { - return internal::ValueArray7(v1, v2, v3, v4, v5, - v6, v7); -} - -template -internal::ValueArray8 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { - return internal::ValueArray8(v1, v2, v3, v4, - v5, v6, v7, v8); -} - -template -internal::ValueArray9 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { - return internal::ValueArray9(v1, v2, v3, - v4, v5, v6, v7, v8, v9); -} - -template -internal::ValueArray10 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { - return internal::ValueArray10(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10); -} - -template -internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) { - return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); -} - -template -internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) { - return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); -} - -template -internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) { - return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); -} - -template -internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { - return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14); -} - -template -internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { - return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15); -} - -template -internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16) { - return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16); -} - -template -internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17) { - return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17); -} - -template -internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18) { - return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18); -} - -template -internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { - return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); -} - -template -internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { - return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); -} - -template -internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { - return internal::ValueArray21(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); -} - -template -internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22) { - return internal::ValueArray22(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22); -} - -template -internal::ValueArray23 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23) { - return internal::ValueArray23(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23); -} - -template -internal::ValueArray24 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24) { - return internal::ValueArray24(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24); -} - -template -internal::ValueArray25 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { - return internal::ValueArray25(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25); -} - -template -internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) { - return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); -} - -template -internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) { - return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); -} - -template -internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) { - return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28); -} - -template -internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) { - return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29); -} - -template -internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { - return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30); -} - -template -internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { - return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31); -} - -template -internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32) { - return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32); -} - -template -internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33) { - return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); -} - -template -internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34) { - return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); -} - -template -internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { - return internal::ValueArray35(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); -} - -template -internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { - return internal::ValueArray36(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36); -} - -template -internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37) { - return internal::ValueArray37(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37); -} - -template -internal::ValueArray38 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38) { - return internal::ValueArray38(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, - v33, v34, v35, v36, v37, v38); -} - -template -internal::ValueArray39 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38, T39 v39) { - return internal::ValueArray39(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, - v32, v33, v34, v35, v36, v37, v38, v39); -} - -template -internal::ValueArray40 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, - T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, - T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { - return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, - v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); -} - -template -internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { - return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, - v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); -} - -template -internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) { - return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, - v42); -} - -template -internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) { - return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, - v41, v42, v43); -} - -template -internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) { - return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, - v40, v41, v42, v43, v44); -} - -template -internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { - return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, - v39, v40, v41, v42, v43, v44, v45); -} - -template -internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { - return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46); -} - -template -internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { - return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); -} - -template -internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, - T48 v48) { - return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, - v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); -} - -template -internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, - T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, - T47 v47, T48 v48, T49 v49) { - return internal::ValueArray49(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, - v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); -} - -template -internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, - T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, - T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { - return internal::ValueArray50(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, - v48, v49, v50); +template +internal::ValueArray Values(T... v) { + return internal::ValueArray(std::move(v)...); } // Bool() allows generating tests with parameters in a set of (false, true). @@ -1207,7 +346,7 @@ internal::ValueArray50 { @@ -1215,13 +354,12 @@ internal::ValueArray50 Bool() { return Values(false, true); } -# if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // @@ -1230,192 +368,136 @@ inline internal::ParamGenerator Bool() { // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of -// tuple where T1, T2, ..., TN are the types +// std::tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // -// Combine can have up to 10 arguments. This number is currently limited -// by the maximum number of elements in the tuple implementation used by Google -// Test. +// Combine can have up to 10 arguments. // // Example: // -// This will instantiate tests in test case AnimalTest each one with +// This will instantiate tests in test suite AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest -// : public testing::TestWithParam > {...}; +// : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // -// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, -// Combine(Values("cat", "dog"), -// Values(BLACK, WHITE))); +// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest -// : public testing::TestWithParam > { +// : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. -// tie(external_flag_1, external_flag_2) = GetParam(); +// std::tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } -// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, -// Combine(Bool(), Bool())); -// -template -internal::CartesianProductHolder2 Combine( - const Generator1& g1, const Generator2& g2) { - return internal::CartesianProductHolder2( - g1, g2); -} - -template -internal::CartesianProductHolder3 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3) { - return internal::CartesianProductHolder3( - g1, g2, g3); -} - -template -internal::CartesianProductHolder4 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4) { - return internal::CartesianProductHolder4( - g1, g2, g3, g4); -} - -template -internal::CartesianProductHolder5 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5) { - return internal::CartesianProductHolder5( - g1, g2, g3, g4, g5); -} - -template -internal::CartesianProductHolder6 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6) { - return internal::CartesianProductHolder6( - g1, g2, g3, g4, g5, g6); -} - -template -internal::CartesianProductHolder7 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7) { - return internal::CartesianProductHolder7( - g1, g2, g3, g4, g5, g6, g7); -} - -template -internal::CartesianProductHolder8 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8) { - return internal::CartesianProductHolder8( - g1, g2, g3, g4, g5, g6, g7, g8); -} - -template -internal::CartesianProductHolder9 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9) { - return internal::CartesianProductHolder9( - g1, g2, g3, g4, g5, g6, g7, g8, g9); -} - -template -internal::CartesianProductHolder10 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9, - const Generator10& g10) { - return internal::CartesianProductHolder10( - g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); -} -# endif // GTEST_HAS_COMBINE - - - -# define TEST_P(test_case_name, test_name) \ - class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - : public test_case_name { \ - public: \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ - virtual void TestBody(); \ - private: \ - static int AddToRegistry() { \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ - #test_case_name, \ - #test_name, \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ - return 0; \ - } \ - static int gtest_registering_dummy_; \ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ - }; \ - int GTEST_TEST_CLASS_NAME_(test_case_name, \ - test_name)::gtest_registering_dummy_ = \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ - void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ - ::testing::internal::ParamGenerator \ - gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - int gtest_##prefix##test_case_name##_dummy_ = \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ +// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder Combine(const Generator&... g) { + return internal::CartesianProductHolder(g...); +} + +#define TEST_P(test_suite_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public test_suite_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + virtual void TestBody(); \ + \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + #test_suite_name, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestPattern( \ + GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory()); \ + return 0; \ + } \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() + +// The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify +// generator and an optional function or functor that generates custom test name +// suffixes based on the test parameters. Such a function or functor should +// accept one argument of type testing::TestParamInfo, and +// return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. + +#define GTEST_EXPAND_(arg) arg +#define GTEST_GET_FIRST_(first, ...) first +#define GTEST_GET_SECOND_(first, second, ...) second + +#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \ + static ::testing::internal::ParamGenerator \ + gtest_##prefix##test_suite_name##_EvalGenerator_() { \ + return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \ + } \ + static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo& info) { \ + if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))); \ + auto t = std::make_tuple(__VA_ARGS__); \ + static_assert(std::tuple_size::value <= 2, \ + "Too Many Args!"); \ + } \ + return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))))(info); \ + } \ + static int gtest_##prefix##test_suite_name##_dummy_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + #test_suite_name, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestSuiteInstantiation( \ + #prefix, >est_##prefix##test_suite_name##_EvalGenerator_, \ + >est_##prefix##test_suite_name##_EvalGenerateName_, \ __FILE__, __LINE__) -} // namespace testing +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TEST_CASE_P \ + static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \ + ""); \ + INSTANTIATE_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ -#endif // GTEST_HAS_PARAM_TEST +} // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/test/gtest/include/gtest/gtest-param-test.h.pump b/test/gtest/include/gtest/gtest-param-test.h.pump index 2dc9303b5e..7b7243f348 100644 --- a/test/gtest/include/gtest/gtest-param-test.h.pump +++ b/test/gtest/include/gtest/gtest-param-test.h.pump @@ -33,7 +33,7 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) +// in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // @@ -78,7 +78,7 @@ TEST_P(FooTest, HasBlahBlah) { // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which +// (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // @@ -184,15 +184,10 @@ TEST_P(DerivedTest, DoesBlah) { # include #endif -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-param-util-generated.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Functions producing parameter generators. @@ -272,7 +267,7 @@ internal::ParamGenerator Range(T start, T end) { // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": @@ -441,8 +436,6 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( ]] # endif // GTEST_HAS_COMBINE - - # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ @@ -453,14 +446,17 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ - #test_case_name, \ - #test_name, \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + #test_case_name, \ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__))->AddTestPattern(\ + GTEST_STRINGIFY_(test_case_name), \ + GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(\ + test_case_name, test_name)>()); \ return 0; \ } \ - static int gtest_registering_dummy_; \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ @@ -469,19 +465,37 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ - ::testing::internal::ParamGenerator \ +// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user +// to specify a function or functor that generates custom test name suffixes +// based on the test parameters. The function should accept one argument of +// type testing::TestParamInfo, and return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ + static ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - int gtest_##prefix##test_case_name##_dummy_ = \ + static ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo& info) { \ + return ::testing::internal::GetParamNameGen \ + (__VA_ARGS__)(info); \ + } \ + static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - __FILE__, __LINE__) + #test_case_name, \ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__))->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + >est_##prefix##test_case_name##_EvalGenerateName_, \ + __FILE__, __LINE__) } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/test/gtest/include/gtest/gtest-printers.h b/test/gtest/include/gtest/gtest-printers.h index b00f91e8c7..56a05450ef 100644 --- a/test/gtest/include/gtest/gtest-printers.h +++ b/test/gtest/include/gtest/gtest-printers.h @@ -26,10 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -46,6 +45,10 @@ // 2. operator<<(ostream&, const T&) defined in either foo or the // global namespace. // +// However if T is an STL-style container then it is printed element-wise +// unless foo::PrintTo(const T&, ostream*) is defined. Note that +// operator<<() is ignored for container types. +// // If none of the above is defined, it will print the debug string of // the value if it is a protocol buffer, or print the raw bytes in the // value otherwise. @@ -92,17 +95,27 @@ // being defined as many user-defined container types don't have // value_type. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ -#pragma GCC system_header +#include #include // NOLINT #include #include +#include +#include #include #include -#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_ABSL +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" +#endif // GTEST_HAS_ABSL namespace testing { @@ -122,7 +135,11 @@ enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) - kOtherType // anything else +#if GTEST_HAS_ABSL + kConvertibleToStringView, // a type implicitly convertible to + // absl::string_view +#endif + kOtherType // anything else }; // TypeWithoutFormatter::PrintValue(value, os) is called @@ -134,8 +151,10 @@ class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(reinterpret_cast(&value), - sizeof(value), os); + PrintBytesInObjectTo( + static_cast( + reinterpret_cast(std::addressof(value))), + sizeof(value), os); } }; @@ -148,10 +167,10 @@ template class TypeWithoutFormatter { public: static void PrintValue(const T& value, ::std::ostream* os) { - const ::testing::internal::string short_str = value.ShortDebugString(); - const ::testing::internal::string pretty_str = - short_str.length() <= kProtobufOneLinerMaxLength ? - short_str : ("\n" + value.DebugString()); + std::string pretty_str = value.ShortDebugString(); + if (pretty_str.length() > kProtobufOneLinerMaxLength) { + pretty_str = "\n" + value.DebugString(); + } *os << ("<" + pretty_str + ">"); } }; @@ -172,6 +191,19 @@ class TypeWithoutFormatter { } }; +#if GTEST_HAS_ABSL +template +class TypeWithoutFormatter { + public: + // Since T has neither operator<< nor PrintTo() but can be implicitly + // converted to absl::string_view, we print it as a absl::string_view. + // + // Note: the implementation is further below, as it depends on + // internal::PrintTo symbol which is defined later in the file. + static void PrintValue(const T& value, ::std::ostream* os); +}; +#endif + // Prints the given value to the given ostream. If the value is a // protocol message, its debug string is printed; if it's an enum or // of a type implicitly convertible to BiggestInt, it's printed as an @@ -199,10 +231,19 @@ class TypeWithoutFormatter { template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { - TypeWithoutFormatter::value ? kProtobuf : - internal::ImplicitlyConvertible::value ? - kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + TypeWithoutFormatter::value + ? kProtobuf + : std::is_convertible< + const T&, internal::BiggestInt>::value + ? kConvertibleToInteger + : +#if GTEST_HAS_ABSL + std::is_convertible< + const T&, absl::string_view>::value + ? kConvertibleToStringView + : +#endif + kOtherType)>::PrintValue(x, &os); return os; } @@ -251,6 +292,93 @@ void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { namespace testing { namespace internal { +// FormatForComparison::Format(value) formats a +// value of type ToPrint that is an operand of a comparison assertion +// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in +// the comparison, and is used to help determine the best way to +// format the value. In particular, when the value is a C string +// (char pointer) and the other operand is an STL string object, we +// want to format the C string as a string, since we know it is +// compared by value with the string object. If the value is a char +// pointer but the other operand is not an STL string object, we don't +// know whether the pointer is supposed to point to a NUL-terminated +// string, and thus want to print it as a pointer to be safe. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// The default case. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint& value) { + return ::testing::PrintToString(value); + } +}; + +// Array. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint* value) { + return FormatForComparison::Format(value); + } +}; + +// By default, print C string as pointers to be safe, as we don't know +// whether they actually point to a NUL-terminated string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ + template \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(static_cast(value)); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ + +// If a C string is compared with an STL string object, we know it's meant +// to point to a NUL-terminated string, and thus can print it as a string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ + template <> \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(value); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); + +#if GTEST_HAS_STD_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); +#endif + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char* or void*, and print it as a C string when it is compared +// against an std::string object, for example. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +std::string FormatForComparisonFailureMessage( + const T1& value, const T2& /* other_operand */) { + return FormatForComparison::Format(value); +} + // UniversalPrinter::Print(value, ostream_ptr) prints the given // value to the given ostream. The caller must ensure that // 'ostream_ptr' is not NULL, or the behavior is undefined. @@ -264,11 +392,18 @@ class UniversalPrinter; template void UniversalPrint(const T& value, ::std::ostream* os); +enum DefaultPrinterType { + kPrintContainer, + kPrintPointer, + kPrintFunctionPointer, + kPrintOther, +}; +template struct WrapPrinterType {}; + // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template -void DefaultPrintTo(IsContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; @@ -301,40 +436,34 @@ void DefaultPrintTo(IsContainer /* dummy */, // implementation-defined. Therefore they will be printed as raw // bytes.) template -void DefaultPrintTo(IsNotContainer /* dummy */, - true_type /* is a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, T* p, ::std::ostream* os) { - if (p == NULL) { + if (p == nullptr) { *os << "NULL"; } else { - // C++ doesn't allow casting from a function pointer to any object - // pointer. - // - // IsTrue() silences warnings: "Condition is always true", - // "unreachable code". - if (IsTrue(ImplicitlyConvertible::value)) { - // T is not a function type. We just call << to print p, - // relying on ADL to pick up user-defined << for their pointer - // types, if any. - *os << p; - } else { - // T is a function type, so '*os << p' doesn't do what we want - // (it just prints p as bool). We want to print p as a const - // void*. However, we cannot cast it to const void* directly, - // even using reinterpret_cast, as earlier versions of gcc - // (e.g. 3.4.5) cannot compile the cast when p is a function - // pointer. Casting to UInt64 first solves the problem. - *os << reinterpret_cast( - reinterpret_cast(p)); - } + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } +} +template +void DefaultPrintTo(WrapPrinterType /* dummy */, + T* p, ::std::ostream* os) { + if (p == nullptr) { + *os << "NULL"; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. + *os << reinterpret_cast(p); } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template -void DefaultPrintTo(IsNotContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } @@ -352,11 +481,8 @@ void DefaultPrintTo(IsNotContainer /* dummy */, // wants). template void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first two - // arguments determine which version will be picked. If T is an - // STL-style container, the version for container will be called; if - // T is a pointer, the pointer version will be called; otherwise the - // generic version will be called. + // DefaultPrintTo() is overloaded. The type of its first argument + // determines which version will be picked. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: @@ -368,13 +494,23 @@ void PrintTo(const T& value, ::std::ostream* os) { // elements; therefore we check for container types here to ensure // that our format is used. // - // The second argument of DefaultPrintTo() is needed to bypass a bug - // in Symbian's C++ compiler that prevents it from picking the right - // overload between: - // - // PrintTo(const T& x, ...); - // PrintTo(T* x, ...); - DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); + // Note that MSVC and clang-cl do allow an implicit conversion from + // pointer-to-function to pointer-to-object, but clang-cl warns on it. + // So don't use ImplicitlyConvertible if it can be helped since it will + // cause this warning, and use a separate overload of DefaultPrintTo for + // function pointers so that the `*os << p` in the object pointer overload + // doesn't cause that warning either. + DefaultPrintTo( + WrapPrinterType < + (sizeof(IsContainerTest(0)) == sizeof(IsContainer)) && + !IsRecursiveContainer::value + ? kPrintContainer + : !std::is_pointer::value + ? kPrintOther + : std::is_function::type>::value + ? kPrintFunctionPointer + : kPrintPointer > (), + value, os); } // The following list of PrintTo() overloads tells @@ -453,27 +589,13 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { } } -// Overloads for ::string and ::std::string. -#if GTEST_HAS_GLOBAL_STRING -GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); -inline void PrintTo(const ::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_STRING - +// Overloads for ::std::string. GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } -// Overloads for ::wstring and ::std::wstring. -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - +// Overloads for ::std::wstring. #if GTEST_HAS_STD_WSTRING GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { @@ -481,86 +603,45 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_TR1_TUPLE -// Overload for ::std::tr1::tuple. Needed for printing function arguments, -// which are packed as tuples. - -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os); - -// Overloaded PrintTo() for tuples of various arities. We support -// tuples of up-to 10 fields. The following implementation works -// regardless of whether tr1::tuple is implemented using the -// non-standard variadic template feature or not. - -inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { - PrintTupleTo(t, os); +#if GTEST_HAS_ABSL +// Overload for absl::string_view. +inline void PrintTo(absl::string_view sp, ::std::ostream* os) { + PrintTo(::std::string(sp), os); } +#endif // GTEST_HAS_ABSL -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} +inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); +template +void PrintTo(std::reference_wrapper ref, ::std::ostream* os) { + UniversalPrinter::Print(ref.get(), os); } -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T&, std::integral_constant, + ::std::ostream*) {} + +template +void PrintTupleTo(const T& t, std::integral_constant, + ::std::ostream* os) { + PrintTupleTo(t, std::integral_constant(), os); + GTEST_INTENTIONAL_CONST_COND_PUSH_() + if (I > 1) { + GTEST_INTENTIONAL_CONST_COND_POP_() + *os << ", "; + } + UniversalPrinter::type>::Print( + std::get(t), os); } -template -void PrintTo( - const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); +template +void PrintTo(const ::std::tuple& t, ::std::ostream* os) { + *os << "("; + PrintTupleTo(t, std::integral_constant(), os); + *os << ")"; } -#endif // GTEST_HAS_TR1_TUPLE // Overload for std::pair. template @@ -581,10 +662,7 @@ class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) // Note: we deliberately don't call this PrintTo(), as that name // conflicts with ::testing::internal::PrintTo in the body of the @@ -601,11 +679,51 @@ class UniversalPrinter { PrintTo(value, os); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() }; +#if GTEST_HAS_ABSL + +// Printer for absl::optional + +template +class UniversalPrinter<::absl::optional> { + public: + static void Print(const ::absl::optional& value, ::std::ostream* os) { + *os << '('; + if (!value) { + *os << "nullopt"; + } else { + UniversalPrint(*value, os); + } + *os << ')'; + } +}; + +// Printer for absl::variant + +template +class UniversalPrinter<::absl::variant> { + public: + static void Print(const ::absl::variant& value, ::std::ostream* os) { + *os << '('; + absl::visit(Visitor{os}, value); + *os << ')'; + } + + private: + struct Visitor { + template + void operator()(const U& u) const { + *os << "'" << GetTypeName() << "' with value "; + UniversalPrint(u, os); + } + ::std::ostream* os; + }; +}; + +#endif // GTEST_HAS_ABSL + // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template @@ -619,7 +737,6 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. - // TODO(wan@google.com): let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { @@ -655,10 +772,7 @@ class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) static void Print(const T& value, ::std::ostream* os) { // Prints the address of the value. We use reinterpret_cast here @@ -669,9 +783,7 @@ class UniversalPrinter { UniversalPrint(value, os); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() }; // Prints a value tersely: for a reference type, the referenced value @@ -703,10 +815,10 @@ template <> class UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { - if (str == NULL) { + if (str == nullptr) { *os << "NULL"; } else { - UniversalPrint(string(str), os); + UniversalPrint(std::string(str), os); } } }; @@ -723,7 +835,7 @@ template <> class UniversalTersePrinter { public: static void Print(const wchar_t* str, ::std::ostream* os) { - if (str == NULL) { + if (str == nullptr) { *os << "NULL"; } else { UniversalPrint(::std::wstring(str), os); @@ -757,77 +869,22 @@ void UniversalPrint(const T& value, ::std::ostream* os) { UniversalPrinter::Print(value, os); } -#if GTEST_HAS_TR1_TUPLE -typedef ::std::vector Strings; - -// This helper template allows PrintTo() for tuples and -// UniversalTersePrintTupleFieldsToStrings() to be defined by -// induction on the number of tuple fields. The idea is that -// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N -// fields in tuple t, and can be defined in terms of -// TuplePrefixPrinter. - -// The inductive case. -template -struct TuplePrefixPrinter { - // Prints the first N fields of a tuple. - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - TuplePrefixPrinter::PrintPrefixTo(t, os); - *os << ", "; - UniversalPrinter::type> - ::Print(::std::tr1::get(t), os); - } +typedef ::std::vector< ::std::string> Strings; // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); - ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Base cases. -template <> -struct TuplePrefixPrinter<0> { - template - static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} - - template - static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} -}; -// We have to specialize the entire TuplePrefixPrinter<> class -// template here, even though the definition of -// TersePrintPrefixToStrings() is the same as the generic version, as -// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't -// support specializing a method template of a class template. -template <> -struct TuplePrefixPrinter<1> { - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - UniversalPrinter::type>:: - Print(::std::tr1::get<0>(t), os); - } - - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get<0>(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os) { - *os << "("; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - PrintPrefixTo(t, os); - *os << ")"; +template +void TersePrintPrefixToStrings(const Tuple&, std::integral_constant, + Strings*) {} +template +void TersePrintPrefixToStrings(const Tuple& t, + std::integral_constant, + Strings* strings) { + TersePrintPrefixToStrings(t, std::integral_constant(), + strings); + ::std::stringstream ss; + UniversalTersePrint(std::get(t), &ss); + strings->push_back(ss.str()); } // Prints the fields of a tuple tersely to a string vector, one @@ -836,14 +893,24 @@ void PrintTupleTo(const T& t, ::std::ostream* os) { template Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - TersePrintPrefixToStrings(value, &result); + TersePrintPrefixToStrings( + value, std::integral_constant::value>(), + &result); return result; } -#endif // GTEST_HAS_TR1_TUPLE } // namespace internal +#if GTEST_HAS_ABSL +namespace internal2 { +template +void TypeWithoutFormatter::PrintValue( + const T& value, ::std::ostream* os) { + internal::PrintTo(absl::string_view(value), os); +} +} // namespace internal2 +#endif + template ::std::string PrintToString(const T& value) { ::std::stringstream ss; @@ -853,4 +920,9 @@ ::std::string PrintToString(const T& value) { } // namespace testing +// Include any custom printer added by the local installation. +// We must include this header at the end to make sure it can use the +// declarations from this file. +#include "gtest/internal/custom/gtest-printers.h" + #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ diff --git a/test/gtest/include/gtest/gtest-spi.h b/test/gtest/include/gtest/gtest-spi.h index f63fa9a1b2..aa38870e8e 100644 --- a/test/gtest/include/gtest/gtest-spi.h +++ b/test/gtest/include/gtest/gtest-spi.h @@ -26,17 +26,21 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). +// GOOGLETEST_CM0004 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #include "gtest/gtest.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // This helper class can be used to mock out Google Test failure reporting @@ -68,14 +72,15 @@ class GTEST_API_ ScopedFakeTestPartResultReporter TestPartResultArray* result); // The d'tor restores the previous test part result reporter. - virtual ~ScopedFakeTestPartResultReporter(); + ~ScopedFakeTestPartResultReporter() override; // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult& result) override; + private: void Init(); @@ -97,13 +102,12 @@ class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr); + TestPartResult::Type type, const std::string& substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; - const string substr_; + const std::string substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; @@ -112,6 +116,8 @@ class GTEST_API_ SingleFailureChecker { } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' diff --git a/test/gtest/include/gtest/gtest-test-part.h b/test/gtest/include/gtest/gtest-test-part.h index 77eb844839..05a7985358 100644 --- a/test/gtest/include/gtest/gtest-test-part.h +++ b/test/gtest/include/gtest/gtest-test-part.h @@ -27,8 +27,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: mheule@google.com (Markus Heule) -// +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ @@ -38,6 +37,9 @@ #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // A copyable object representing the result of a test part (i.e. an @@ -51,22 +53,20 @@ class GTEST_API_ TestPartResult { enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. - kFatalFailure // Failed and the test should be terminated. + kFatalFailure, // Failed and the test should be terminated. + kSkip // Skipped. }; // C'tor. TestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestPartResult object. - TestPartResult(Type a_type, - const char* a_file_name, - int a_line_number, + TestPartResult(Type a_type, const char* a_file_name, int a_line_number, const char* a_message) : type_(a_type), - file_name_(a_file_name == NULL ? "" : a_file_name), + file_name_(a_file_name == nullptr ? "" : a_file_name), line_number_(a_line_number), summary_(ExtractSummary(a_message)), - message_(a_message) { - } + message_(a_message) {} // Gets the outcome of the test part. Type type() const { return type_; } @@ -74,7 +74,7 @@ class GTEST_API_ TestPartResult { // Gets the name of the source file where the test part took place, or // NULL if it's unknown. const char* file_name() const { - return file_name_.empty() ? NULL : file_name_.c_str(); + return file_name_.empty() ? nullptr : file_name_.c_str(); } // Gets the line in the source file where the test part took place, @@ -87,18 +87,21 @@ class GTEST_API_ TestPartResult { // Gets the message associated with the test part. const char* message() const { return message_.c_str(); } - // Returns true iff the test part passed. - bool passed() const { return type_ == kSuccess; } + // Returns true if and only if the test part was skipped. + bool skipped() const { return type_ == kSkip; } - // Returns true iff the test part failed. - bool failed() const { return type_ != kSuccess; } + // Returns true if and only if the test part passed. + bool passed() const { return type_ == kSuccess; } - // Returns true iff the test part non-fatally failed. + // Returns true if and only if the test part non-fatally failed. bool nonfatally_failed() const { return type_ == kNonFatalFailure; } - // Returns true iff the test part fatally failed. + // Returns true if and only if the test part fatally failed. bool fatally_failed() const { return type_ == kFatalFailure; } + // Returns true if and only if the test part failed. + bool failed() const { return fatally_failed() || nonfatally_failed(); } + private: Type type_; @@ -143,7 +146,7 @@ class GTEST_API_ TestPartResultArray { }; // This interface knows how to report a test part result. -class TestPartResultReporterInterface { +class GTEST_API_ TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} @@ -162,8 +165,8 @@ class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); - virtual ~HasNewFatalFailureHelper(); - virtual void ReportTestPartResult(const TestPartResult& result); + ~HasNewFatalFailureHelper() override; + void ReportTestPartResult(const TestPartResult& result) override; bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; @@ -176,4 +179,6 @@ class GTEST_API_ HasNewFatalFailureHelper } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ diff --git a/test/gtest/include/gtest/gtest-typed-test.h b/test/gtest/include/gtest/gtest-typed-test.h index d5dc8be1c2..095ce05802 100644 --- a/test/gtest/include/gtest/gtest-typed-test.h +++ b/test/gtest/include/gtest/gtest-typed-test.h @@ -26,12 +26,12 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + + +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ -#pragma GCC system_header // This header implements typed tests and type-parameterized tests. @@ -52,22 +52,22 @@ class FooTest : public testing::Test { T value_; }; -// Next, associate a list of types with the test case, which will be +// Next, associate a list of types with the test suite, which will be // repeated for each type in the list. The typedef is necessary for // the macro to parse correctly. typedef testing::Types MyTypes; -TYPED_TEST_CASE(FooTest, MyTypes); +TYPED_TEST_SUITE(FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: -// TYPED_TEST_CASE(FooTest, int); +// TYPED_TEST_SUITE(FooTest, int); // Then, use TYPED_TEST() instead of TEST_F() to define as many typed -// tests for this test case as you want. +// tests for this test suite as you want. TYPED_TEST(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - // Since we are inside a derived class template, C++ requires use to - // visit the members of FooTest via 'this'. + // Inside a test, refer to the special name TypeParam to get the type + // parameter. Since we are inside a derived class template, C++ requires + // us to visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the TestFixture:: @@ -83,6 +83,24 @@ TYPED_TEST(FooTest, DoesBlah) { TYPED_TEST(FooTest, HasPropertyA) { ... } +// TYPED_TEST_SUITE takes an optional third argument which allows to specify a +// class that generates custom test name suffixes based on the type. This should +// be a class which has a static template function GetName(int index) returning +// a string for each type. The provided integer index equals the index of the +// type in the provided type list. In many cases the index can be ignored. +// +// For example: +// class MyTypeNames { +// public: +// template +// static std::string GetName(int) { +// if (std::is_same()) return "char"; +// if (std::is_same()) return "int"; +// if (std::is_same()) return "unsignedInt"; +// } +// }; +// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames); + #endif // 0 // Type-parameterized tests are abstract test patterns parameterized @@ -108,13 +126,13 @@ class FooTest : public testing::Test { ... }; -// Next, declare that you will define a type-parameterized test case +// Next, declare that you will define a type-parameterized test suite // (the _P suffix is for "parameterized" or "pattern", whichever you // prefer): -TYPED_TEST_CASE_P(FooTest); +TYPED_TEST_SUITE_P(FooTest); // Then, use TYPED_TEST_P() to define as many type-parameterized tests -// for this type-parameterized test case as you want. +// for this type-parameterized test suite as you want. TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; @@ -125,10 +143,10 @@ TYPED_TEST_P(FooTest, HasPropertyA) { ... } // Now the tricky part: you need to register all test patterns before // you can instantiate them. The first argument of the macro is the -// test case name; the rest are the names of the tests in this test +// test suite name; the rest are the names of the tests in this test // case. -REGISTER_TYPED_TEST_CASE_P(FooTest, - DoesBlah, HasPropertyA); +REGISTER_TYPED_TEST_SUITE_P(FooTest, + DoesBlah, HasPropertyA); // Finally, you are free to instantiate the pattern with the types you // want. If you put the above code in a header file, you can #include @@ -136,14 +154,19 @@ REGISTER_TYPED_TEST_CASE_P(FooTest, // // To distinguish different instances of the pattern, the first // argument to the INSTANTIATE_* macro is a prefix that will be added -// to the actual test case name. Remember to pick unique prefixes for +// to the actual test suite name. Remember to pick unique prefixes for // different instances. typedef testing::Types MyTypes; -INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: -// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); +// +// Similar to the optional argument of TYPED_TEST_SUITE above, +// INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to +// generate custom names. +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames); #endif // 0 @@ -157,34 +180,53 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the -// given test case. -# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define TYPED_TEST_CASE(CaseName, Types) \ - typedef ::testing::internal::TypeList< Types >::type \ - GTEST_TYPE_PARAMS_(CaseName) - -# define TYPED_TEST(CaseName, TestName) \ - template \ - class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ - : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTest< \ - CaseName, \ - ::testing::internal::TemplateSel< \ - GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ - GTEST_TYPE_PARAMS_(CaseName)>::Register(\ - "", #CaseName, #TestName, 0); \ - template \ - void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() +// given test suite. +#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_ + +// Expands to the name of the typedef for the NameGenerator, responsible for +// creating the suffixes of the name. +#define GTEST_NAME_GENERATOR_(TestSuiteName) \ + gtest_type_params_##TestSuiteName##_NameGenerator + +#define TYPED_TEST_SUITE(CaseName, Types, ...) \ + typedef ::testing::internal::TypeList::type GTEST_TYPE_PARAMS_( \ + CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ + GTEST_NAME_GENERATOR_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##CaseName##_##TestName##_registered_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel, \ + GTEST_TYPE_PARAMS_( \ + CaseName)>::Register("", \ + ::testing::internal::CodeLocation( \ + __FILE__, __LINE__), \ + #CaseName, #TestName, 0, \ + ::testing::internal::GenerateNames< \ + GTEST_NAME_GENERATOR_(CaseName), \ + GTEST_TYPE_PARAMS_(CaseName)>()); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, \ + TestName)::TestBody() + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE \ + static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \ + TYPED_TEST_SUITE +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_HAS_TYPED_TEST @@ -195,65 +237,93 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for -// the given type-parameterized test case are defined in. The exact +// the given type-parameterized test suite are defined in. The exact // name of the namespace is subject to change without notice. -# define GTEST_CASE_NAMESPACE_(TestCaseName) \ - gtest_case_##TestCaseName##_ +#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the variable used to remember the names of -// the defined tests in the given test case. -# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ - gtest_typed_test_case_p_state_##TestCaseName##_ +// the defined tests in the given test suite. +#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \ + gtest_typed_test_suite_p_state_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. // // Expands to the name of the variable used to remember the names of -// the registered tests in the given test case. -# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ - gtest_registered_test_names_##TestCaseName##_ +// the registered tests in the given test suite. +#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \ + gtest_registered_test_names_##TestSuiteName##_ // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. -# define TYPED_TEST_CASE_P(CaseName) \ - static ::testing::internal::TypedTestCasePState \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) - -# define TYPED_TEST_P(CaseName, TestName) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - template \ - class TestName : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ - __FILE__, __LINE__, #CaseName, #TestName); \ - } \ - template \ - void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() - -# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ - } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ +#define TYPED_TEST_SUITE_P(SuiteName) \ + static ::testing::internal::TypedTestSuitePState \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE_P \ + static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \ + TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define TYPED_TEST_P(SuiteName, TestName) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + template \ + class TestName : public SuiteName { \ + private: \ + typedef SuiteName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ + __FILE__, __LINE__, #SuiteName, #TestName); \ + } \ + template \ + void GTEST_SUITE_NAMESPACE_( \ + SuiteName)::TestName::TestBody() + +#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_( \ + SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ __FILE__, __LINE__, #__VA_ARGS__) -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ - bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTestCase::type>::Register(\ - #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define REGISTER_TYPED_TEST_CASE_P \ + static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \ + ""); \ + REGISTER_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ + static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestSuite< \ + SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ + ::testing::internal::TypeList::type>:: \ + Register(#Prefix, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), #SuiteName, \ + GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ + ::testing::internal::GenerateNames< \ + ::testing::internal::NameGeneratorSelector< \ + __VA_ARGS__>::type, \ + ::testing::internal::TypeList::type>()) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TYPED_TEST_CASE_P \ + static_assert( \ + ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \ + INSTANTIATE_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_HAS_TYPED_TEST_P diff --git a/test/gtest/include/gtest/gtest.h b/test/gtest/include/gtest/gtest.h index 6fa0a3925e..dbe5b1c2c3 100644 --- a/test/gtest/include/gtest/gtest.h +++ b/test/gtest/include/gtest/gtest.h @@ -26,10 +26,9 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. @@ -48,16 +47,22 @@ // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ +#include #include +#include #include +#include #include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" #include "gtest/gtest-death-test.h" +#include "gtest/gtest-matchers.h" #include "gtest/gtest-message.h" #include "gtest/gtest-param-test.h" #include "gtest/gtest-printers.h" @@ -65,23 +70,20 @@ #include "gtest/gtest-test-part.h" #include "gtest/gtest-typed-test.h" -// Depending on the platform, different string classes are available. -// On Linux, in addition to ::std::string, Google also makes use of -// class ::string, which has the same interface as ::std::string, but -// has a different implementation. -// -// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that -// ::string is available AND is a distinct type to ::std::string, or -// define it to 0 to indicate otherwise. -// -// If the user's ::std::string and ::string are the same class due to -// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. -// -// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined -// heuristically. +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) namespace testing { +// Silence C4100 (unreferenced formal parameter) and 4805 +// unsafe mix of type 'const int' and type 'const bool' +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4805) +# pragma warning(disable:4100) +#endif + + // Declares the flags. // This flag temporary enables the disabled tests. @@ -103,6 +105,10 @@ GTEST_DECLARE_string_(color); // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); +// This flag controls whether Google Test installs a signal handler that dumps +// debugging information when fatal signals are raised. +GTEST_DECLARE_bool_(install_failure_signal_handler); + // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); @@ -115,6 +121,9 @@ GTEST_DECLARE_string_(output); // test. GTEST_DECLARE_bool_(print_time); +// This flags control whether Google Test prints UTF8 characters as text. +GTEST_DECLARE_bool_(print_utf8); + // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); @@ -135,7 +144,7 @@ GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a -// non-zero code otherwise. +// non-zero code otherwise. For use with an external test framework. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported @@ -143,6 +152,10 @@ GTEST_DECLARE_bool_(throw_on_failure); // the specified host machine. GTEST_DECLARE_string_(stream_result_to); +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DECLARE_string_(flagfile); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; @@ -160,6 +173,7 @@ class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; +class FuchsiaDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); @@ -170,7 +184,12 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; -class TestCase; +class TestSuite; + +// Old API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TestCase = TestSuite; +#endif class TestInfo; class UnitTest; @@ -258,10 +277,38 @@ class GTEST_API_ AssertionResult { // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); + +#if defined(_MSC_VER) && _MSC_VER < 1910 + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) +#endif + // Used in the EXPECT_TRUE/FALSE(bool_expression). - explicit AssertionResult(bool success) : success_(success) {} + // + // T must be contextually convertible to bool. + // + // The second parameter prevents this overload from being considered if + // the argument is implicitly convertible to AssertionResult. In that case + // we want AssertionResult's copy constructor to be used. + template + explicit AssertionResult( + const T& success, + typename std::enable_if< + !std::is_convertible::value>::type* + /*enabler*/ + = nullptr) + : success_(success) {} + +#if defined(_MSC_VER) && _MSC_VER < 1910 + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + + // Assignment operator. + AssertionResult& operator=(AssertionResult other) { + swap(other); + return *this; + } - // Returns true iff the assertion succeeded. + // Returns true if and only if the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. @@ -272,9 +319,8 @@ class GTEST_API_ AssertionResult { // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { - return message_.get() != NULL ? message_->c_str() : ""; + return message_.get() != nullptr ? message_->c_str() : ""; } - // TODO(vladl@google.com): Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } @@ -295,20 +341,20 @@ class GTEST_API_ AssertionResult { private: // Appends the contents of message to message_. void AppendMessage(const Message& a_message) { - if (message_.get() == NULL) - message_.reset(new ::std::string); + if (message_.get() == nullptr) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } + // Swap the contents of this AssertionResult with other. + void swap(AssertionResult& other); + // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. - internal::scoped_ptr< ::std::string> message_; - - GTEST_DISALLOW_ASSIGN_(AssertionResult); + std::unique_ptr< ::std::string> message_; }; // Makes a successful assertion result. @@ -321,22 +367,31 @@ GTEST_API_ AssertionResult AssertionFailure(); // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); +} // namespace testing + +// Includes the auto-generated header that implements a family of generic +// predicate assertion macros. This include comes late because it relies on +// APIs declared above. +#include "gtest/gtest_pred_impl.h" + +namespace testing { + // The abstract class that all tests inherit from. // -// In Google Test, a unit test program contains one or many TestCases, and -// each TestCase contains one or many Tests. +// In Google Test, a unit test program contains one or many TestSuites, and +// each TestSuite contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does // this for you. // // The only time you derive from Test is when defining a test fixture -// to be used a TEST_F. For example: +// to be used in a TEST_F. For example: // // class FooTest : public testing::Test { // protected: -// virtual void SetUp() { ... } -// virtual void TearDown() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } // ... // }; // @@ -348,49 +403,57 @@ class GTEST_API_ Test { public: friend class TestInfo; - // Defines types for pointers to functions that set up and tear down - // a test case. - typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; - typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; - // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // - // Google Test will call Foo::SetUpTestCase() before running the first + // Google Test will call Foo::SetUpTestSuite() before running the first // test in test case Foo. Hence a sub-class can define its own - // SetUpTestCase() method to shadow the one defined in the super + // SetUpTestSuite() method to shadow the one defined in the super // class. - static void SetUpTestCase() {} + // Failures that happen during SetUpTestSuite are logged but otherwise + // ignored. + static void SetUpTestSuite() {} - // Tears down the stuff shared by all tests in this test case. + // Tears down the stuff shared by all tests in this test suite. // - // Google Test will call Foo::TearDownTestCase() after running the last + // Google Test will call Foo::TearDownTestSuite() after running the last // test in test case Foo. Hence a sub-class can define its own - // TearDownTestCase() method to shadow the one defined in the super + // TearDownTestSuite() method to shadow the one defined in the super // class. + // Failures that happen during TearDownTestSuite are logged but otherwise + // ignored. + static void TearDownTestSuite() {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ static void TearDownTestCase() {} + static void SetUpTestCase() {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ - // Returns true iff the current test has a fatal failure. + // Returns true if and only if the current test has a fatal failure. static bool HasFatalFailure(); - // Returns true iff the current test has a non-fatal failure. + // Returns true if and only if the current test has a non-fatal failure. static bool HasNonfatalFailure(); - // Returns true iff the current test has a (either fatal or + // Returns true if and only if the current test was skipped. + static bool IsSkipped(); + + // Returns true if and only if the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } - // Logs a property for the current test, test case, or for the entire + // Logs a property for the current test, test suite, or for the entire // invocation of the test program when used outside of the context of a - // test case. Only the last value for a given key is remembered. These + // test suite. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the element. Properties recorded from fixture's - // SetUpTestCase or TearDownTestCase are logged as attributes of the + // SetUpTestSuite or TearDownTestSuite are logged as attributes of the // corresponding element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google @@ -409,8 +472,8 @@ class GTEST_API_ Test { virtual void TearDown(); private: - // Returns true iff the current test has the same fixture class as - // the first test in the current test case. + // Returns true if and only if the current test has the same fixture class + // as the first test in the current test suite. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. @@ -428,27 +491,26 @@ class GTEST_API_ Test { // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } - // Uses a GTestFlagSaver to save and restore all Google Test flags. - const internal::GTestFlagSaver* const gtest_flag_saver_; + const std::unique_ptr gtest_flag_saver_; - // Often a user mis-spells SetUp() as Setup() and spends a long time + // Often a user misspells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it - // will be a conflict if a user declares void Setup() in his test - // fixture. + // will be a conflict if void Setup() is declared in the user's + // test fixture. // // - This method is private, so it will be another compiler error - // if a user calls it from his test fixture. + // if the method is called from the user's test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); @@ -512,24 +574,30 @@ class GTEST_API_ TestResult { // Returns the number of the test properties. int test_property_count() const; - // Returns true iff the test passed (i.e. no test part failed). - bool Passed() const { return !Failed(); } + // Returns true if and only if the test passed (i.e. no test part failed). + bool Passed() const { return !Skipped() && !Failed(); } - // Returns true iff the test failed. + // Returns true if and only if the test was skipped. + bool Skipped() const; + + // Returns true if and only if the test failed. bool Failed() const; - // Returns true iff the test fatally failed. + // Returns true if and only if the test fatally failed. bool HasFatalFailure() const; - // Returns true iff the test has a non-fatal failure. + // Returns true if and only if the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } - // Returns the i-th test part result among all the results. i can range - // from 0 to test_property_count() - 1. If i is not in that range, aborts - // the program. + // Gets the time of the test case start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + + // Returns the i-th test part result among all the results. i can range from 0 + // to total_part_count() - 1. If i is not in that range, aborts the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to @@ -539,13 +607,14 @@ class GTEST_API_ TestResult { private: friend class TestInfo; - friend class TestCase; + friend class TestSuite; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; + friend class internal::FuchsiaDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { @@ -557,6 +626,9 @@ class GTEST_API_ TestResult { return test_properties_; } + // Sets the start time. + void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; } + // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } @@ -570,8 +642,8 @@ class GTEST_API_ TestResult { const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test - // testcase tags. Returns true if the property is valid. - // TODO(russr): Validate attribute names are legal and human readable. + // testsuite tags. Returns true if the property is valid. + // FIXME: Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); @@ -600,6 +672,8 @@ class GTEST_API_ TestResult { std::vector test_properties_; // Running count of death tests. int death_test_count_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; @@ -609,7 +683,7 @@ class GTEST_API_ TestResult { // A TestInfo object stores the following information about a test: // -// Test case name +// Test suite name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked @@ -624,8 +698,13 @@ class GTEST_API_ TestInfo { // don't inherit from TestInfo. ~TestInfo(); - // Returns the test case name. - const char* test_case_name() const { return test_case_name_.c_str(); } + // Returns the test suite name. + const char* test_suite_name() const { return test_suite_name_.c_str(); } + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const char* test_case_name() const { return test_suite_name(); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the test name. const char* name() const { return name_.c_str(); } @@ -633,25 +712,32 @@ class GTEST_API_ TestInfo { // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. const char* value_param() const { - if (value_param_.get() != NULL) - return value_param_->c_str(); - return NULL; + if (value_param_.get() != nullptr) return value_param_->c_str(); + return nullptr; } + // Returns the file name where this test is defined. + const char* file() const { return location_.file.c_str(); } + + // Returns the line where this test is defined. + int line() const { return location_.line; } + + // Return true if this test should not be run because it's in another shard. + bool is_in_another_shard() const { return is_in_another_shard_; } + // Returns true if this test should run, that is if the test is not // disabled (or it is disabled but the also_run_disabled_tests flag has // been specified) and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. - // The full name of a test Bar in test case Foo is defined as + // The full name of a test Bar in test suite Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, @@ -664,12 +750,11 @@ class GTEST_API_ TestInfo { // contains the character 'A' or starts with "Foo.". bool should_run() const { return should_run_; } - // Returns true iff this test will appear in the XML report. + // Returns true if and only if this test will appear in the XML report. bool is_reportable() const { - // For now, the XML report includes all tests matching the filter. - // In the future, we may trim tests that are excluded because of - // sharding. - return matches_filter_; + // The XML report includes tests matching the filter, excluding those + // run in other shards. + return matches_filter_ && !is_in_another_shard_; } // Returns the result of the test. @@ -680,25 +765,22 @@ class GTEST_API_ TestInfo { friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; - friend class TestCase; + friend class TestSuite; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; friend TestInfo* internal::MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - internal::TypeId fixture_class_id, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, internal::CodeLocation code_location, + internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, internal::TestFactoryBase* factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. - TestInfo(const std::string& test_case_name, - const std::string& name, + TestInfo(const std::string& test_suite_name, const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test + internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); @@ -717,19 +799,21 @@ class GTEST_API_ TestInfo { } // These fields are immutable properties of the test. - const std::string test_case_name_; // Test case name + const std::string test_suite_name_; // test suite name const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. - const internal::scoped_ptr type_param_; + const std::unique_ptr type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. - const internal::scoped_ptr value_param_; - const internal::TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled - bool matches_filter_; // True if this test matches the - // user-specified filter. + const std::unique_ptr value_param_; + internal::CodeLocation location_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True if and only if this test should run + bool is_disabled_; // True if and only if this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + bool is_in_another_shard_; // Will be run in another shard. internal::TestFactoryBase* const factory_; // The factory that creates // the test object @@ -740,90 +824,96 @@ class GTEST_API_ TestInfo { GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; -// A test case, which consists of a vector of TestInfos. +// A test suite, which consists of a vector of TestInfos. // -// TestCase is not copyable. -class GTEST_API_ TestCase { +// TestSuite is not copyable. +class GTEST_API_ TestSuite { public: - // Creates a TestCase with the given name. + // Creates a TestSuite with the given name. // - // TestCase does NOT have a default constructor. Always use this - // constructor to create a TestCase object. + // TestSuite does NOT have a default constructor. Always use this + // constructor to create a TestSuite object. // // Arguments: // - // name: name of the test case + // name: name of the test suite // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite(const char* name, const char* a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); - // Destructor of TestCase. - virtual ~TestCase(); + // Destructor of TestSuite. + virtual ~TestSuite(); - // Gets the name of the TestCase. + // Gets the name of the TestSuite. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a - // type-parameterized test case. + // type-parameterized test suite. const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; } - // Returns true if any test in this test case should run. + // Returns true if any test in this test suite should run. bool should_run() const { return should_run_; } - // Gets the number of successful tests in this test case. + // Gets the number of successful tests in this test suite. int successful_test_count() const; - // Gets the number of failed tests in this test case. + // Gets the number of skipped tests in this test suite. + int skipped_test_count() const; + + // Gets the number of failed tests in this test suite. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; - // Gets the number of disabled tests in this test case. + // Gets the number of disabled tests in this test suite. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; - // Get the number of tests in this test case that should run. + // Get the number of tests in this test suite that should run. int test_to_run_count() const; - // Gets the number of all tests in this test case. + // Gets the number of all tests in this test suite. int total_test_count() const; - // Returns true iff the test case passed. + // Returns true if and only if the test suite passed. bool Passed() const { return !Failed(); } - // Returns true iff the test case failed. + // Returns true if and only if the test suite failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } + // Gets the time of the test suite start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; // Returns the TestResult that holds test properties recorded during - // execution of SetUpTestCase and TearDownTestCase. + // execution of SetUpTestSuite and TearDownTestSuite. const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; - // Gets the (mutable) vector of TestInfos in this TestCase. + // Gets the (mutable) vector of TestInfos in this TestSuite. std::vector& test_info_list() { return test_info_list_; } - // Gets the (immutable) vector of TestInfos in this TestCase. + // Gets the (immutable) vector of TestInfos in this TestSuite. const std::vector& test_info_list() const { return test_info_list_; } @@ -835,51 +925,64 @@ class GTEST_API_ TestCase { // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } - // Adds a TestInfo to this test case. Will delete the TestInfo upon - // destruction of the TestCase object. + // Adds a TestInfo to this test suite. Will delete the TestInfo upon + // destruction of the TestSuite object. void AddTestInfo(TestInfo * test_info); - // Clears the results of all tests in this test case. + // Clears the results of all tests in this test suite. void ClearResult(); - // Clears the results of all tests in the given test case. - static void ClearTestCaseResult(TestCase* test_case) { - test_case->ClearResult(); + // Clears the results of all tests in the given test suite. + static void ClearTestSuiteResult(TestSuite* test_suite) { + test_suite->ClearResult(); } - // Runs every test in this TestCase. + // Runs every test in this TestSuite. void Run(); - // Runs SetUpTestCase() for this TestCase. This wrapper is needed - // for catching exceptions thrown from SetUpTestCase(). - void RunSetUpTestCase() { (*set_up_tc_)(); } + // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed + // for catching exceptions thrown from SetUpTestSuite(). + void RunSetUpTestSuite() { + if (set_up_tc_ != nullptr) { + (*set_up_tc_)(); + } + } - // Runs TearDownTestCase() for this TestCase. This wrapper is - // needed for catching exceptions thrown from TearDownTestCase(). - void RunTearDownTestCase() { (*tear_down_tc_)(); } + // Runs TearDownTestSuite() for this TestSuite. This wrapper is + // needed for catching exceptions thrown from TearDownTestSuite(). + void RunTearDownTestSuite() { + if (tear_down_tc_ != nullptr) { + (*tear_down_tc_)(); + } + } - // Returns true iff test passed. + // Returns true if and only if test passed. static bool TestPassed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Passed(); } - // Returns true iff test failed. + // Returns true if and only if test skipped. + static bool TestSkipped(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Skipped(); + } + + // Returns true if and only if test failed. static bool TestFailed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Failed(); } - // Returns true iff the test is disabled and will be reported in the XML - // report. + // Returns true if and only if the test is disabled and will be reported in + // the XML report. static bool TestReportableDisabled(const TestInfo* test_info) { return test_info->is_reportable() && test_info->is_disabled_; } - // Returns true iff test is disabled. + // Returns true if and only if test is disabled. static bool TestDisabled(const TestInfo* test_info) { return test_info->is_disabled_; } - // Returns true iff this test will appear in the XML report. + // Returns true if and only if this test will appear in the XML report. static bool TestReportable(const TestInfo* test_info) { return test_info->is_reportable(); } @@ -889,17 +992,17 @@ class GTEST_API_ TestCase { return test_info->should_run(); } - // Shuffles the tests in this test case. + // Shuffles the tests in this test suite. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); - // Name of the test case. + // Name of the test suite. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. - const internal::scoped_ptr type_param_; + const std::unique_ptr type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector test_info_list_; @@ -907,24 +1010,26 @@ class GTEST_API_ TestCase { // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; - // Pointer to the function that sets up the test case. - Test::SetUpTestCaseFunc set_up_tc_; - // Pointer to the function that tears down the test case. - Test::TearDownTestCaseFunc tear_down_tc_; - // True iff any test in this test case should run. + // Pointer to the function that sets up the test suite. + internal::SetUpTestSuiteFunc set_up_tc_; + // Pointer to the function that tears down the test suite. + internal::TearDownTestSuiteFunc tear_down_tc_; + // True if and only if any test in this test suite should run. bool should_run_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; - // Holds test properties recorded during execution of SetUpTestCase and - // TearDownTestCase. + // Holds test properties recorded during execution of SetUpTestSuite and + // TearDownTestSuite. TestResult ad_hoc_test_result_; - // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); + // We disallow copying TestSuites. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestSuite); }; // An Environment object is capable of setting up and tearing down an -// environment. The user should subclass this to define his own +// environment. You should subclass this to define your own // environment(s). // // An Environment object does the set-up and tear-down in virtual @@ -951,9 +1056,21 @@ class Environment { // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } }; +#if GTEST_HAS_EXCEPTIONS + +// Exception which can be thrown from TestEventListener::OnTestPartResult. +class GTEST_API_ AssertionException + : public internal::GoogleTestFailureException { + public: + explicit AssertionException(const TestPartResult& result) + : GoogleTestFailureException(result) {} +}; + +#endif // GTEST_HAS_EXCEPTIONS + // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { @@ -975,20 +1092,32 @@ class TestEventListener { // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; - // Fired before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; + // Fired before the test suite starts. + virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. + // If you want to throw an exception from this function to skip to the next + // TEST, it must be AssertionException defined above, or inherited from it. virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; - // Fired after the test case ends. - virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + // Fired after the test suite ends. + virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; @@ -1011,21 +1140,30 @@ class TestEventListener { // above. class EmptyTestEventListener : public TestEventListener { public: - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} - virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} + void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {} +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnTestStart(const TestInfo& /*test_info*/) override {} + void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {} + void OnTestEnd(const TestInfo& /*test_info*/) override {} + void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} }; // TestEventListeners lets users add listeners to track events in Google Test. @@ -1065,7 +1203,7 @@ class GTEST_API_ TestEventListeners { } private: - friend class TestCase; + friend class TestSuite; friend class TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; @@ -1106,7 +1244,7 @@ class GTEST_API_ TestEventListeners { GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; -// A UnitTest consists of a vector of TestCases. +// A UnitTest consists of a vector of TestSuites. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This @@ -1135,10 +1273,14 @@ class GTEST_API_ UnitTest { // was executed. The UnitTest object owns the string. const char* original_working_dir() const; - // Returns the TestCase object for the test that's currently running, + // Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. - const TestCase* current_test_case() const - GTEST_LOCK_EXCLUDED_(mutex_); + const TestSuite* current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_); + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); +#endif // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. @@ -1148,31 +1290,40 @@ class GTEST_API_ UnitTest { // Returns the random seed used at the start of the current test run. int random_seed() const; -#if GTEST_HAS_PARAM_TEST - // Returns the ParameterizedTestCaseRegistry object used to keep track of + // Returns the ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() + internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); -#endif // GTEST_HAS_PARAM_TEST - // Gets the number of successful test cases. - int successful_test_case_count() const; + // Gets the number of successful test suites. + int successful_test_suite_count() const; - // Gets the number of failed test cases. - int failed_test_case_count() const; + // Gets the number of failed test suites. + int failed_test_suite_count() const; - // Gets the number of all test cases. - int total_test_case_count() const; + // Gets the number of all test suites. + int total_test_suite_count() const; - // Gets the number of all test cases that contain at least one test + // Gets the number of all test suites that contain at least one test // that should run. + int test_suite_to_run_count() const; + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + int successful_test_case_count() const; + int failed_test_case_count() const; + int total_test_case_count() const; int test_case_to_run_count() const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the number of successful tests. int successful_test_count() const; + // Gets the number of skipped tests. + int skipped_test_count() const; + // Gets the number of failed tests. int failed_test_count() const; @@ -1198,19 +1349,25 @@ class GTEST_API_ UnitTest { // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; - // Returns true iff the unit test passed (i.e. all test cases passed). + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). bool Passed() const; - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). bool Failed() const; - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite* GetTestSuite(int i) const; + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* GetTestCase(int i) const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the TestResult containing information on test failures and - // properties logged outside of individual test cases. + // properties logged outside of individual test suites. const TestResult& ad_hoc_test_result() const; // Returns the list of event listeners that can be used to track events @@ -1241,25 +1398,25 @@ class GTEST_API_ UnitTest { GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from - // inside a test, to current TestCase's ad_hoc_test_result_ when invoked - // from SetUpTestCase or TearDownTestCase, or to the global property set + // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked + // from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void RecordProperty(const std::string& key, const std::string& value); - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i); + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite* GetMutableTestSuite(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } - // These classes and funcions are friends as they need to access private + // These classes and functions are friends as they need to access private // members of UnitTest. + friend class ScopedTrace; friend class Test; friend class internal::AssertHelper; - friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); @@ -1334,155 +1491,67 @@ GTEST_API_ void InitGoogleTest(int* argc, char** argv); // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); -namespace internal { - -// FormatForComparison::Format(value) formats a -// value of type ToPrint that is an operand of a comparison assertion -// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in -// the comparison, and is used to help determine the best way to -// format the value. In particular, when the value is a C string -// (char pointer) and the other operand is an STL string object, we -// want to format the C string as a string, since we know it is -// compared by value with the string object. If the value is a char -// pointer but the other operand is not an STL string object, we don't -// know whether the pointer is supposed to point to a NUL-terminated -// string, and thus want to print it as a pointer to be safe. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - -// The default case. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint& value) { - return ::testing::PrintToString(value); - } -}; - -// Array. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint* value) { - return FormatForComparison::Format(value); - } -}; - -// By default, print C string as pointers to be safe, as we don't know -// whether they actually point to a NUL-terminated string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ - template \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(static_cast(value)); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ - -// If a C string is compared with an STL string object, we know it's meant -// to point to a NUL-terminated string, and thus can print it as a string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ - template <> \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(value); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); - -#if GTEST_HAS_GLOBAL_STRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); -#endif - -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); -#endif +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +GTEST_API_ void InitGoogleTest(); -#if GTEST_HAS_STD_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); -#endif - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ +namespace internal { -// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) -// operand to be used in a failure message. The type (but not value) -// of the other operand may affect the format. This allows us to -// print a char* as a raw pointer when it is compared against another -// char* or void*, and print it as a C string when it is compared -// against an std::string object, for example. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers +// when calling EXPECT_* in a tight loop. template -std::string FormatForComparisonFailureMessage( - const T1& value, const T2& /* other_operand */) { - return FormatForComparison::Format(value); +AssertionResult CmpHelperEQFailure(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, const T2& rhs) { + return EqFailure(lhs_expression, + rhs_expression, + FormatForComparisonFailureMessage(lhs, rhs), + FormatForComparisonFailureMessage(rhs, lhs), + false); } +// This block of code defines operator==/!= +// to block lexical scope lookup. +// It prevents using invalid operator==/!= defined at namespace scope. +struct faketype {}; +inline bool operator==(faketype, faketype) { return true; } +inline bool operator!=(faketype, faketype) { return false; } + // The helper function for {ASSERT|EXPECT}_EQ. template -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4389) // Temporarily disables warning on - // signed/unsigned mismatch. -#endif - - if (expected == actual) { +AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, + const T2& rhs) { + if (lhs == rhs) { return AssertionSuccess(); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif - - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); + return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. -GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual); - -// The helper class for {ASSERT|EXPECT}_EQ. The template argument -// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() -// is a null pointer literal. The following default implementation is -// for lhs_is_null_literal being false. -template +GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs); + class EqHelper { public: // This templatized version is for the general case. - template - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); + template < + typename T1, typename T2, + // Disable this overload for cases where one argument is a pointer + // and the other is the null pointer constant. + typename std::enable_if::value || + !std::is_pointer::value>::type* = nullptr> + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, const T1& lhs, + const T2& rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } // With this overloaded version, we allow anonymous enums to be used @@ -1491,60 +1560,37 @@ class EqHelper { // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } -}; - -// This specialization is used when the first argument to ASSERT_EQ() -// is a null pointer literal, like NULL, false, or 0. -template <> -class EqHelper { - public: - // We define two overloaded versions of Compare(). The first - // version will be picked when the second argument to ASSERT_EQ() is - // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or - // EXPECT_EQ(false, a_bool). - template - static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual, - // The following line prevents this overload from being considered if T2 - // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) - // expands to Compare("", "", NULL, my_ptr), which requires a conversion - // to match the Secret* in the other overload, which would otherwise make - // this template match better. - typename EnableIf::value>::type* = 0) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } - // This version will be picked when the second argument to ASSERT_EQ() is a - // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, - // We used to have a second template parameter instead of Secret*. That - // template parameter would deduce to 'long', making this a better match - // than the first overload even without the first overload's EnableIf. - // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to - // non-pointer argument" (even a deduced integral argument), so the old - // implementation caused warnings in user code. - Secret* /* expected (NULL) */, - T* actual) { - // We already know that 'expected' is a null pointer. - return CmpHelperEQ(expected_expression, actual_expression, - static_cast(NULL), actual); + const char* lhs_expression, const char* rhs_expression, + // Handle cases where '0' is used as a null pointer literal. + std::nullptr_t /* lhs */, T* rhs) { + // We already know that 'lhs' is a null pointer. + return CmpHelperEQ(lhs_expression, rhs_expression, static_cast(nullptr), + rhs); } }; +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers +// when calling EXPECT_OP in a tight loop. +template +AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, + const T1& val1, const T2& val2, + const char* op) { + return AssertionFailure() + << "Expected: (" << expr1 << ") " << op << " (" << expr2 + << "), actual: " << FormatForComparisonFailureMessage(val1, val2) + << " vs " << FormatForComparisonFailureMessage(val2, val1); +} + // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. @@ -1555,6 +1601,7 @@ class EqHelper { // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ @@ -1562,10 +1609,7 @@ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ - return AssertionFailure() \ - << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ @@ -1589,18 +1633,18 @@ GTEST_IMPL_CMP_HELPER_(GT, >); // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); // The helper function for {ASSERT|EXPECT}_STRNE. // @@ -1622,10 +1666,10 @@ GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual); +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); // Helper function for *_STRNE on wide strings. // @@ -1683,28 +1727,28 @@ namespace internal { // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template -AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, - const char* actual_expression, - RawType expected, - RawType actual) { - const FloatingPoint lhs(expected), rhs(actual); +AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, + const char* rhs_expression, + RawType lhs_value, + RawType rhs_value) { + const FloatingPoint lhs(lhs_value), rhs(rhs_value); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } - ::std::stringstream expected_ss; - expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << expected; + ::std::stringstream lhs_ss; + lhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << lhs_value; - ::std::stringstream actual_ss; - actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << actual; + ::std::stringstream rhs_ss; + rhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << rhs_value; - return EqFailure(expected_expression, - actual_expression, - StringStreamToString(&expected_ss), - StringStreamToString(&actual_ss), + return EqFailure(lhs_expression, + rhs_expression, + StringStreamToString(&lhs_ss), + StringStreamToString(&rhs_ss), false); } @@ -1759,9 +1803,14 @@ class GTEST_API_ AssertHelper { GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; +enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; + +GTEST_API_ GTEST_ATTRIBUTE_PRINTF_(2, 3) void ColoredPrintf(GTestColor color, + const char* fmt, + ...); + } // namespace internal -#if GTEST_HAS_PARAM_TEST // The pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting @@ -1779,13 +1828,13 @@ class GTEST_API_ AssertHelper { // FooTest() { // // Can use GetParam() here. // } -// virtual ~FooTest() { +// ~FooTest() override { // // Can use GetParam() here. // } -// virtual void SetUp() { +// void SetUp() override { // // Can use GetParam() here. // } -// virtual void TearDown { +// void TearDown override { // // Can use GetParam() here. // } // }; @@ -1794,7 +1843,7 @@ class GTEST_API_ AssertHelper { // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } -// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); +// INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class WithParamInterface { @@ -1803,12 +1852,9 @@ class WithParamInterface { virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's - // constructor. This member function is non-static, even though it only - // references static data, to reduce the opportunity for incorrect uses - // like writing 'WithParamInterface::GetParam()' for a test that - // uses a fixture whose parameter type is int. - const ParamType& GetParam() const { - GTEST_CHECK_(parameter_ != NULL) + // constructor. + static const ParamType& GetParam() { + GTEST_CHECK_(parameter_ != nullptr) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; return *parameter_; @@ -1829,7 +1875,7 @@ class WithParamInterface { }; template -const T* WithParamInterface::parameter_ = NULL; +const T* WithParamInterface::parameter_ = nullptr; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. @@ -1838,10 +1884,13 @@ template class TestWithParam : public Test, public WithParamInterface { }; -#endif // GTEST_HAS_PARAM_TEST - // Macros for indicating success/failure in test code. +// Skips test in runtime. +// Skipping test aborts current function. +// Skipped tests are neither successful nor failed. +#define GTEST_SKIP() GTEST_SKIP_("Skipped") + // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has @@ -1871,6 +1920,11 @@ class TestWithParam : public Test, public WithParamInterface { // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") +// Like GTEST_FAIL(), but at the given source file location. +#define GTEST_FAIL_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kFatalFailure) + // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL @@ -1924,18 +1978,14 @@ class TestWithParam : public Test, public WithParamInterface { GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) -// Includes the auto-generated header that implements a family of -// generic predicate assertion macros. -#include "gtest/gtest_pred_impl.h" - // Macros for testing equalities and inequalities. // -// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual -// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 -// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 -// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 -// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 -// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2 +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, @@ -1957,8 +2007,8 @@ class TestWithParam : public Test, public WithParamInterface { // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // -// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to -// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// 3. {ASSERT|EXPECT}_EQ(v1, v2) is preferred to +// {ASSERT|EXPECT}_TRUE(v1 == v2), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // @@ -1969,17 +2019,15 @@ class TestWithParam : public Test, public WithParamInterface { // // Examples: // -// EXPECT_NE(5, Foo()); -// EXPECT_EQ(NULL, a_pointer); +// EXPECT_NE(Foo(), 5); +// EXPECT_EQ(a_pointer, NULL); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; -#define EXPECT_EQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) -#define EXPECT_NE(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) +#define EXPECT_EQ(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) +#define EXPECT_NE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ @@ -1989,10 +2037,8 @@ class TestWithParam : public Test, public WithParamInterface { #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) -#define GTEST_ASSERT_EQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) +#define GTEST_ASSERT_EQ(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ @@ -2047,29 +2093,29 @@ class TestWithParam : public Test, public WithParamInterface { // // These macros evaluate their arguments exactly once. -#define EXPECT_STREQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STREQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define EXPECT_STRCASEEQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASEEQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) -#define ASSERT_STREQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STREQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define ASSERT_STRCASEEQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASEEQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // -// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2): // Tests that two float values are almost equal. -// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. @@ -2079,21 +2125,21 @@ class TestWithParam : public Test, public WithParamInterface { // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. -#define EXPECT_FLOAT_EQ(expected, actual)\ +#define EXPECT_FLOAT_EQ(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) -#define EXPECT_DOUBLE_EQ(expected, actual)\ +#define EXPECT_DOUBLE_EQ(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) -#define ASSERT_FLOAT_EQ(expected, actual)\ +#define ASSERT_FLOAT_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) -#define ASSERT_DOUBLE_EQ(expected, actual)\ +#define ASSERT_DOUBLE_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ @@ -2156,6 +2202,51 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) +// Causes a trace (including the given source file path and line number, +// and the given message) to be included in every test failure message generated +// by code in the scope of the lifetime of an instance of this class. The effect +// is undone with the destruction of the instance. +// +// The message argument can be anything streamable to std::ostream. +// +// Example: +// testing::ScopedTrace trace("file.cc", 123, "message"); +// +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + + // Template version. Uses Message() to convert the values into strings. + // Slow, but flexible. + template + ScopedTrace(const char* file, int line, const T& message) { + PushTrace(file, line, (Message() << message).GetString()); + } + + // Optimize for some known types. + ScopedTrace(const char* file, int line, const char* message) { + PushTrace(file, line, message ? message : "(null)"); + } + + ScopedTrace(const char* file, int line, const std::string& message) { + PushTrace(file, line, message); + } + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + void PushTrace(const char* file, int line, std::string message); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is @@ -2167,13 +2258,17 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. +// +// Assuming that each thread maintains its own stack of traces. +// Therefore, a SCOPED_TRACE() would (correctly) only affect the +// assertions in its own thread. #define SCOPED_TRACE(message) \ - ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ - __FILE__, __LINE__, ::testing::Message() << (message)) + ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, (message)) // Compile-time assertion for type equality. -// StaticAssertTypeEq() compiles iff type1 and type2 are -// the same type. The value it returns is not interesting. +// StaticAssertTypeEq() compiles if and only if type1 and type2 +// are the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This @@ -2202,21 +2297,22 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // // to cause a compiler error. template -bool StaticAssertTypeEq() { - (void)internal::StaticAssertTypeEqHelper(); +constexpr bool StaticAssertTypeEq() noexcept { + static_assert(std::is_same::value, + "type1 and type2 are not the same type"); return true; } // Defines a test. // -// The first parameter is the name of the test case, and the second -// parameter is the name of the test within the test case. +// The first parameter is the name of the test suite, and the second +// parameter is the name of the test within the test suite. // -// The convention is to end the test case name with "Test". For -// example, a test case for the Foo class can be named FooTest. +// The convention is to end the test suite name with "Test". For +// example, a test suite for the Foo class can be named FooTest. // -// The user should put his test code between braces after using this -// macro. Example: +// Test code should appear between braces after an invocation of +// this macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; @@ -2232,28 +2328,28 @@ bool StaticAssertTypeEq() { // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. -#define GTEST_TEST(test_case_name, test_name)\ - GTEST_TEST_(test_case_name, test_name, \ - ::testing::Test, ::testing::internal::GetTestTypeId()) +#define GTEST_TEST(test_suite_name, test_name) \ + GTEST_TEST_(test_suite_name, test_name, ::testing::Test, \ + ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST -# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which -// also doubles as the test case name. The second parameter is the -// name of the test within the test case. +// also doubles as the test suite name. The second parameter is the +// name of the test within the test suite. // // A test fixture class must be declared earlier. The user should put -// his test code between braces after using this macro. Example: +// the test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: -// virtual void SetUp() { b_.AddElement(3); } +// void SetUp() override { b_.AddElement(3); } // // Foo a_; // Foo b_; @@ -2264,14 +2360,103 @@ bool StaticAssertTypeEq() { // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { -// EXPECT_EQ(0, a_.size()); -// EXPECT_EQ(1, b_.size()); +// EXPECT_EQ(a_.size(), 0); +// EXPECT_EQ(b_.size(), 1); // } - +// +// GOOGLETEST_CM0011 DO NOT DELETE #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) +// Returns a path to temporary directory. +// Tries to determine an appropriate directory for the platform. +GTEST_API_ std::string TempDir(); + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +// Dynamically registers a test with the framework. +// +// This is an advanced API only to be used when the `TEST` macros are +// insufficient. The macros should be preferred when possible, as they avoid +// most of the complexity of calling this function. +// +// The `factory` argument is a factory callable (move-constructible) object or +// function pointer that creates a new instance of the Test object. It +// handles ownership to the caller. The signature of the callable is +// `Fixture*()`, where `Fixture` is the test fixture class for the test. All +// tests registered with the same `test_suite_name` must return the same +// fixture type. This is checked at runtime. +// +// The framework will infer the fixture class from the factory and will call +// the `SetUpTestSuite` and `TearDownTestSuite` for it. +// +// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is +// undefined. +// +// Use case example: +// +// class MyFixture : public ::testing::Test { +// public: +// // All of these optional, just like in regular macro usage. +// static void SetUpTestSuite() { ... } +// static void TearDownTestSuite() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } +// }; +// +// class MyTest : public MyFixture { +// public: +// explicit MyTest(int data) : data_(data) {} +// void TestBody() override { ... } +// +// private: +// int data_; +// }; +// +// void RegisterMyTests(const std::vector& values) { +// for (int v : values) { +// ::testing::RegisterTest( +// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, +// std::to_string(v).c_str(), +// __FILE__, __LINE__, +// // Important to use the fixture type as the return type here. +// [=]() -> MyFixture* { return new MyTest(v); }); +// } +// } +// ... +// int main(int argc, char** argv) { +// std::vector values_to_test = LoadValuesFromConfig(); +// RegisterMyTests(values_to_test); +// ... +// return RUN_ALL_TESTS(); +// } +// +template +TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, + const char* type_param, const char* value_param, + const char* file, int line, Factory factory) { + using TestT = typename std::remove_pointer::type; + + class FactoryImpl : public internal::TestFactoryBase { + public: + explicit FactoryImpl(Factory f) : factory_(std::move(f)) {} + Test* CreateTest() override { return factory_(); } + + private: + Factory factory_; + }; + + return internal::MakeAndRegisterTestInfo( + test_suite_name, test_name, type_param, value_param, + internal::CodeLocation(file, line), internal::GetTypeId(), + internal::SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + internal::SuiteApiResolver::GetTearDownCaseOrSuite(file, line), + new FactoryImpl{std::move(factory)}); +} + } // namespace testing // Use this function in main() to run all tests. It returns 0 if all @@ -2288,4 +2473,6 @@ inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/test/gtest/include/gtest/gtest_pred_impl.h b/test/gtest/include/gtest/gtest_pred_impl.h index 30ae712f50..d514255c73 100644 --- a/test/gtest/include/gtest/gtest_pred_impl.h +++ b/test/gtest/include/gtest/gtest_pred_impl.h @@ -27,18 +27,18 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command +// This file is AUTOMATICALLY GENERATED on 01/02/2019 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -// Makes sure this header is not included before gtest.h. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ +#include "gtest/gtest.h" + +namespace testing { // This header implements a family of generic predicate assertion // macros: @@ -90,9 +90,10 @@ AssertionResult AssertPred1Helper(const char* pred_text, const T1& v1) { if (pred(v1)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1; + return AssertionFailure() + << pred_text << "(" << e1 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. @@ -134,11 +135,12 @@ AssertionResult AssertPred2Helper(const char* pred_text, const T2& v2) { if (pred(v1, v2)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. @@ -185,13 +187,13 @@ AssertionResult AssertPred3Helper(const char* pred_text, const T3& v3) { if (pred(v1, v2, v3)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. @@ -243,15 +245,14 @@ AssertionResult AssertPred4Helper(const char* pred_text, const T4& v4) { if (pred(v1, v2, v3, v4)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. @@ -308,17 +309,15 @@ AssertionResult AssertPred5Helper(const char* pred_text, const T5& v5) { if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ", " - << e5 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4 - << "\n" << e5 << " evaluates to " << v5; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ", " << e5 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n" + << e5 << " evaluates to " << ::testing::PrintToString(v5); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. @@ -355,4 +354,6 @@ AssertionResult AssertPred5Helper(const char* pred_text, +} // namespace testing + #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ diff --git a/test/gtest/include/gtest/gtest_prod.h b/test/gtest/include/gtest/gtest_prod.h index da80ddc6c7..e651671ebd 100644 --- a/test/gtest/include/gtest/gtest_prod.h +++ b/test/gtest/include/gtest/gtest_prod.h @@ -26,10 +26,10 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// Google C++ Testing Framework definitions useful in production code. +// Google C++ Testing and Mocking Framework definitions useful in production code. +// GOOGLETEST_CM0003 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ @@ -40,17 +40,20 @@ // // class MyClass { // private: -// void MyMethod(); -// FRIEND_TEST(MyClassTest, MyMethod); +// void PrivateMethod(); +// FRIEND_TEST(MyClassTest, PrivateMethodWorks); // }; // // class MyClassTest : public testing::Test { // // ... // }; // -// TEST_F(MyClassTest, MyMethod) { -// // Can call MyClass::MyMethod() here. +// TEST_F(MyClassTest, PrivateMethodWorks) { +// // Can call MyClass::PrivateMethod() here. // } +// +// Note: The test class must be in the same namespace as the class being tested. +// For example, putting MyClassTest in an anonymous namespace will not work. #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test diff --git a/test/gtest/include/gtest/internal/custom/README.md b/test/gtest/include/gtest/internal/custom/README.md new file mode 100644 index 0000000000..ff391fb4e2 --- /dev/null +++ b/test/gtest/include/gtest/internal/custom/README.md @@ -0,0 +1,56 @@ +# Customization Points + +The custom directory is an injection point for custom user configurations. + +## Header `gtest.h` + +### The following macros can be defined: + +* `GTEST_OS_STACK_TRACE_GETTER_` - The name of an implementation of + `OsStackTraceGetterInterface`. +* `GTEST_CUSTOM_TEMPDIR_FUNCTION_` - An override for `testing::TempDir()`. See + `testing::TempDir` for semantics and signature. + +## Header `gtest-port.h` + +The following macros can be defined: + +### Flag related macros: + +* `GTEST_FLAG(flag_name)` +* `GTEST_USE_OWN_FLAGFILE_FLAG_` - Define to 0 when the system provides its + own flagfile flag parsing. +* `GTEST_DECLARE_bool_(name)` +* `GTEST_DECLARE_int32_(name)` +* `GTEST_DECLARE_string_(name)` +* `GTEST_DEFINE_bool_(name, default_val, doc)` +* `GTEST_DEFINE_int32_(name, default_val, doc)` +* `GTEST_DEFINE_string_(name, default_val, doc)` + +### Logging: + +* `GTEST_LOG_(severity)` +* `GTEST_CHECK_(condition)` +* Functions `LogToStderr()` and `FlushInfoLog()` have to be provided too. + +### Threading: + +* `GTEST_HAS_NOTIFICATION_` - Enabled if Notification is already provided. +* `GTEST_HAS_MUTEX_AND_THREAD_LOCAL_` - Enabled if `Mutex` and `ThreadLocal` + are already provided. Must also provide `GTEST_DECLARE_STATIC_MUTEX_(mutex)` + and `GTEST_DEFINE_STATIC_MUTEX_(mutex)` +* `GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)` +* `GTEST_LOCK_EXCLUDED_(locks)` + +### Underlying library support features + +* `GTEST_HAS_CXXABI_H_` + +### Exporting API symbols: + +* `GTEST_API_` - Specifier for exported symbols. + +## Header `gtest-printers.h` + +* See documentation at `gtest/gtest-printers.h` for details on how to define a + custom printer. diff --git a/test/gtest/include/gtest/internal/custom/gtest-port.h b/test/gtest/include/gtest/internal/custom/gtest-port.h new file mode 100644 index 0000000000..cd85d956d2 --- /dev/null +++ b/test/gtest/include/gtest/internal/custom/gtest-port.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ diff --git a/test/gtest/include/gtest/internal/custom/gtest-printers.h b/test/gtest/include/gtest/internal/custom/gtest-printers.h new file mode 100644 index 0000000000..eb4467abca --- /dev/null +++ b/test/gtest/include/gtest/internal/custom/gtest-printers.h @@ -0,0 +1,42 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. +// +// This file provides an injection point for custom printers in a local +// installation of gTest. +// It will be included from gtest-printers.h and the overrides in this file +// will be visible to everyone. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ diff --git a/test/gtest/include/gtest/internal/custom/gtest.h b/test/gtest/include/gtest/internal/custom/gtest.h new file mode 100644 index 0000000000..4c8e07be23 --- /dev/null +++ b/test/gtest/include/gtest/internal/custom/gtest.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ diff --git a/test/gtest/include/gtest/internal/gtest-death-test-internal.h b/test/gtest/include/gtest/internal/gtest-death-test-internal.h index 2b3a78f5bf..68bd353061 100644 --- a/test/gtest/include/gtest/internal/gtest-death-test-internal.h +++ b/test/gtest/include/gtest/internal/gtest-death-test-internal.h @@ -27,19 +27,20 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#include "gtest/gtest-matchers.h" #include "gtest/internal/gtest-internal.h" #include +#include namespace testing { namespace internal { @@ -53,6 +54,9 @@ const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test @@ -76,7 +80,7 @@ class GTEST_API_ DeathTest { // argument is set. If the death test should be skipped, the pointer // is set to NULL; otherwise, it is set to the address of a new concrete // DeathTest object that controls the execution of the current test. - static bool Create(const char* statement, const RE* regex, + static bool Create(const char* statement, Matcher matcher, const char* file, int line, DeathTest** test); DeathTest(); virtual ~DeathTest() { } @@ -136,25 +140,50 @@ class GTEST_API_ DeathTest { GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: virtual ~DeathTestFactory() { } - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) = 0; + virtual bool Create(const char* statement, + Matcher matcher, const char* file, + int line, DeathTest** test) = 0; }; // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); + bool Create(const char* statement, Matcher matcher, + const char* file, int line, DeathTest** test) override; }; // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. GTEST_API_ bool ExitedUnsuccessfully(int exit_status); +// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads +// and interpreted as a regex (rather than an Eq matcher) for legacy +// compatibility. +inline Matcher MakeDeathTestMatcher( + ::testing::internal::RE regex) { + return ContainsRegex(regex.pattern()); +} +inline Matcher MakeDeathTestMatcher(const char* regex) { + return ContainsRegex(regex); +} +inline Matcher MakeDeathTestMatcher( + const ::std::string& regex) { + return ContainsRegex(regex); +} + +// If a Matcher is passed to EXPECT_DEATH (etc.), it's +// used directly. +inline Matcher MakeDeathTestMatcher( + Matcher matcher) { + return matcher; +} + // Traps C++ exceptions escaping statement and reports them as test // failures. Note that trapping SEH exceptions is not implemented here. # if GTEST_HAS_EXCEPTIONS @@ -182,50 +211,53 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, // ASSERT_EXIT*, and EXPECT_EXIT*. -# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - const ::testing::internal::RE& gtest_regex = (regex); \ - ::testing::internal::DeathTest* gtest_dt; \ - if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ - __FILE__, __LINE__, >est_dt)) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - if (gtest_dt != NULL) { \ - ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ - gtest_dt_ptr(gtest_dt); \ - switch (gtest_dt->AssumeRole()) { \ - case ::testing::internal::DeathTest::OVERSEE_TEST: \ - if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - break; \ - case ::testing::internal::DeathTest::EXECUTE_TEST: { \ - ::testing::internal::DeathTest::ReturnSentinel \ - gtest_sentinel(gtest_dt); \ - GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ - gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ - break; \ - } \ - default: \ - break; \ - } \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ - fail(::testing::internal::DeathTest::LastMessage()) +#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create( \ + #statement, \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != nullptr) { \ + std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \ + gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \ + : fail(::testing::internal::DeathTest::LastMessage()) // The symbol "fail" here expands to something into which a message // can be streamed. // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in -// NDEBUG mode. In this case we need the statements to be executed, the regex is -// ignored, and the macro must accept a streamed message even though the message -// is never printed. -# define GTEST_EXECUTE_STATEMENT_(statement, regex) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } else \ +// NDEBUG mode. In this case we need the statements to be executed and the macro +// must accept a streamed message even though the message is never printed. +// The regex object is not evaluated, but it is used to prevent "unused" +// warnings and to avoid an expression that doesn't compile in debug mode. +#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else if (!::testing::internal::AlwaysTrue()) { \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \ + } else \ ::testing::Message() // A class representing the parsed contents of the @@ -264,53 +296,6 @@ class InternalRunDeathTestFlag { // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); -#else // GTEST_HAS_DEATH_TEST - -// This macro is used for implementing macros such as -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where -// death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. -// -// Parameters: -// statement - A statement that a macro such as EXPECT_DEATH would test -// for program termination. This macro has to make sure this -// statement is compiled but not executed, to ensure that -// EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. -// regex - A regex that a macro such as EXPECT_DEATH would use to test -// the output of statement. This parameter has to be -// compiled but not evaluated by this macro, to ensure that -// this macro only accepts expressions that a macro such as -// EXPECT_DEATH would accept. -// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED -// and a return statement for ASSERT_DEATH_IF_SUPPORTED. -// This ensures that ASSERT_DEATH_IF_SUPPORTED will not -// compile inside functions where ASSERT_DEATH doesn't -// compile. -// -// The branch that has an always false condition is used to ensure that -// statement and regex are compiled (and thus syntactically correct) but -// never executed. The unreachable code macro protects the terminator -// statement from generating an 'unreachable code' warning in case -// statement unconditionally returns or throws. The Message constructor at -// the end allows the syntax of streaming additional messages into the -// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. -# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_LOG_(WARNING) \ - << "Death tests are not supported on this platform.\n" \ - << "Statement '" #statement "' cannot be verified."; \ - } else if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::RE::PartialMatch(".*", (regex)); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - terminator; \ - } else \ - ::testing::Message() - #endif // GTEST_HAS_DEATH_TEST } // namespace internal diff --git a/test/gtest/include/gtest/internal/gtest-filepath.h b/test/gtest/include/gtest/internal/gtest-filepath.h index 7a13b4b0de..c11b101516 100644 --- a/test/gtest/include/gtest/internal/gtest-filepath.h +++ b/test/gtest/include/gtest/internal/gtest-filepath.h @@ -27,21 +27,24 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: keith.ray@gmail.com (Keith Ray) -// // Google Test filepath utilities // // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // -// This file is #included in . +// This file is #included in gtest/internal/gtest-internal.h. // Do not include this header file separately! +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #include "gtest/internal/gtest-string.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { namespace internal { @@ -107,7 +110,7 @@ class GTEST_API_ FilePath { const FilePath& base_name, const char* extension); - // Returns true iff the path is "". + // Returns true if and only if the path is "". bool IsEmpty() const { return pathname_.empty(); } // If input name has a trailing separator character, removes it and returns @@ -203,4 +206,6 @@ class GTEST_API_ FilePath { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ diff --git a/test/gtest/include/gtest/internal/gtest-internal.h b/test/gtest/include/gtest/internal/gtest-internal.h index 0dcc3a3194..94c816a28b 100644 --- a/test/gtest/include/gtest/internal/gtest-internal.h +++ b/test/gtest/include/gtest/internal/gtest-internal.h @@ -27,13 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ @@ -55,11 +55,15 @@ #include #include #include +#include #include +#include +#include +#include #include "gtest/gtest-message.h" -#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-type-util.h" // Due to C++ preprocessor weirdness, we need double indirection to @@ -73,7 +77,9 @@ #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar -class ProtocolMessage; +// Stringifies its argument. +#define GTEST_STRINGIFY_(name) #name + namespace proto2 { class Message; } namespace testing { @@ -85,7 +91,7 @@ class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. -class UnitTest; // A collection of test cases. +class UnitTest; // A collection of test suites. template ::std::string PrintToString(const T& value); @@ -93,45 +99,29 @@ ::std::string PrintToString(const T& value); namespace internal { struct TraceInfo; // Information about a trace point. -class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest -// How many times InitGoogleTest() has been called. -GTEST_API_ extern int g_init_gtest_count; - // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; -// Two overloaded helpers for checking at compile time whether an -// expression is a null pointer literal (i.e. NULL or any 0-valued -// compile-time integral constant). Their return values have -// different sizes, so we can use sizeof() to test which version is -// picked by the compiler. These helpers have no implementations, as -// we only need their signatures. -// -// Given IsNullLiteralHelper(x), the compiler will pick the first -// version if x can be implicitly converted to Secret*, and pick the -// second version otherwise. Since Secret is a secret and incomplete -// type, the only expression a user can write that has type Secret* is -// a null pointer literal. Therefore, we know that x is a null -// pointer literal if and only if the first version is picked by the -// compiler. -char IsNullLiteralHelper(Secret* p); -char (&IsNullLiteralHelper(...))[2]; // NOLINT - -// A compile-time bool constant that is true if and only if x is a -// null pointer literal (i.e. NULL or any 0-valued compile-time -// integral constant). -#ifdef GTEST_ELLIPSIS_NEEDS_POD_ -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_IS_NULL_LITERAL_(x) false -#else -# define GTEST_IS_NULL_LITERAL_(x) \ - (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) -#endif // GTEST_ELLIPSIS_NEEDS_POD_ +// An IgnoredValue object can be implicitly constructed from ANY value. +class IgnoredValue { + struct Sink {}; + public: + // This constructor template allows any value to be implicitly + // converted to IgnoredValue. The object has no data member and + // doesn't try to remember anything about the argument. We + // deliberately omit the 'explicit' keyword in order to allow the + // conversion to be implicit. + // Disable the conversion if T already has a magical conversion operator. + // Otherwise we get ambiguity. + template ::value, + int>::type = 0> + IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit) +}; // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ std::string AppendUserMessage( @@ -139,6 +129,9 @@ GTEST_API_ std::string AppendUserMessage( #if GTEST_HAS_EXCEPTIONS +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \ +/* an exported class was derived from a class that was not exported */) + // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions // are enabled). We derive it from std::runtime_error, which is for @@ -150,26 +143,39 @@ class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { explicit GoogleTestFailureException(const TestPartResult& failure); }; -#endif // GTEST_HAS_EXCEPTIONS - -// A helper class for creating scoped traces in user programs. -class GTEST_API_ ScopedTrace { - public: - // The c'tor pushes the given source file location and message onto - // a trace stack maintained by Google Test. - ScopedTrace(const char* file, int line, const Message& message); +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275 - // The d'tor pops the info pushed by the c'tor. - // - // Note that the d'tor is not virtual in order to be efficient. - // Don't inherit from ScopedTrace! - ~ScopedTrace(); +#endif // GTEST_HAS_EXCEPTIONS - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); -} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its - // c'tor and d'tor. Therefore it doesn't - // need to be used otherwise. +namespace edit_distance { +// Returns the optimal edits to go from 'left' to 'right'. +// All edits cost the same, with replace having lower priority than +// add/remove. +// Simple implementation of the Wagner-Fischer algorithm. +// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm +enum EditType { kMatch, kAdd, kRemove, kReplace }; +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, const std::vector& right); + +// Same as above, but the input is represented as strings. +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right); + +// Create a diff of the input strings in Unified diff format. +GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context = 2); + +} // namespace edit_distance + +// Calculate the diff between 'left' and 'right' and return it in unified diff +// format. +// If not null, stores in 'total_line_count' the total number of lines found +// in left + right. +GTEST_API_ std::string DiffStrings(const std::string& left, + const std::string& right, + size_t* total_line_count); // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. @@ -183,7 +189,7 @@ class GTEST_API_ ScopedTrace { // expected_value: "5" // actual_value: "6" // -// The ignoring_case parameter is true iff the assertion is a +// The ignoring_case parameter is true if and only if the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, @@ -312,15 +318,15 @@ class FloatingPoint { // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } - // Returns true iff this is NAN (not a number). + // Returns true if and only if this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } - // Returns true iff this number is at most kMaxUlps ULP's away from - // rhs. In particular, this function: + // Returns true if and only if this number is at most kMaxUlps ULP's away + // from rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. @@ -391,7 +397,7 @@ typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different -// test fixture classes in the same test case, we need to assign +// test fixture classes in the same test suite, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare @@ -451,7 +457,7 @@ class TestFactoryBase { template class TestFactoryImpl : public TestFactoryBase { public: - virtual Test* CreateTest() { return new TestClass; } + Test* CreateTest() override { return new TestClass; } }; #if GTEST_OS_WINDOWS @@ -467,36 +473,93 @@ GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, #endif // GTEST_OS_WINDOWS -// Types of SetUpTestCase() and TearDownTestCase() functions. -typedef void (*SetUpTestCaseFunc)(); -typedef void (*TearDownTestCaseFunc)(); +// Types of SetUpTestSuite() and TearDownTestSuite() functions. +using SetUpTestSuiteFunc = void (*)(); +using TearDownTestSuiteFunc = void (*)(); + +struct CodeLocation { + CodeLocation(const std::string& a_file, int a_line) + : file(a_file), line(a_line) {} + + std::string file; + int line; +}; + +// Helper to identify which setup function for TestCase / TestSuite to call. +// Only one function is allowed, either TestCase or TestSute but not both. + +// Utility functions to help SuiteApiResolver +using SetUpTearDownSuiteFuncType = void (*)(); + +inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull( + SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) { + return a == def ? nullptr : a; +} + +template +// Note that SuiteApiResolver inherits from T because +// SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way +// SuiteApiResolver can access them. +struct SuiteApiResolver : T { + // testing::Test is only forward declared at this point. So we make it a + // dependend class for the compiler to be OK with it. + using Test = + typename std::conditional::type; + + static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both SetUpTestSuite and SetUpTestCase, please " + "make sure there is only one present at " + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } + + static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both TearDownTestSuite and TearDownTestCase," + " please make sure there is only one present at" + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } +}; // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // -// test_case_name: name of the test case +// test_suite_name: name of the test suite // name: name of the test // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param text representation of the test's value parameter, // or NULL if this is not a type-parameterized test. +// code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory); + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged @@ -505,27 +568,42 @@ GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P -// State of the definition of a type-parameterized test case. -class GTEST_API_ TypedTestCasePState { +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +// State of the definition of a type-parameterized test suite. +class GTEST_API_ TypedTestSuitePState { public: - TypedTestCasePState() : registered_(false) {} + TypedTestSuitePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true - // if the test case hasn't been registered; otherwise aborts the + // if the test suite hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { - fprintf(stderr, "%s Test %s must be defined before " - "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + fprintf(stderr, + "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); } - defined_test_names_.insert(test_name); + registered_tests_.insert( + ::std::make_pair(test_name, CodeLocation(file, line))); return true; } + bool TestExists(const std::string& test_name) const { + return registered_tests_.count(test_name) > 0; + } + + const CodeLocation& GetCodeLocation(const std::string& test_name) const { + RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); + GTEST_CHECK_(it != registered_tests_.end()); + return it->second; + } + // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. @@ -533,16 +611,25 @@ class GTEST_API_ TypedTestCasePState { const char* file, int line, const char* registered_tests); private: + typedef ::std::map RegisteredTestsMap; + bool registered_; - ::std::set defined_test_names_; + RegisteredTestsMap registered_tests_; }; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TypedTestCasePState = TypedTestSuitePState; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); - if (comma == NULL) { - return NULL; + if (comma == nullptr) { + return nullptr; } while (IsSpace(*(++comma))) {} return comma; @@ -552,7 +639,43 @@ inline const char* SkipComma(const char* str) { // the entire string if it contains no comma. inline std::string GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); - return comma == NULL ? str : std::string(str, comma); + return comma == nullptr ? str : std::string(str, comma); +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest); + +// The default argument to the template below for the case when the user does +// not provide a name generator. +struct DefaultNameGenerator { + template + static std::string GetName(int i) { + return StreamableToString(i); + } +}; + +template +struct NameGeneratorSelector { + typedef Provided type; +}; + +template +void GenerateNamesRecursively(Types0, std::vector*, int) {} + +template +void GenerateNamesRecursively(Types, std::vector* result, int i) { + result->push_back(NameGenerator::template GetName(i)); + GenerateNamesRecursively(typename Types::Tail(), result, + i + 1); +} + +template +std::vector GenerateNames() { + std::vector result; + GenerateNamesRecursively(Types(), &result, 0); + return result; } // TypeParameterizedTest::Register() @@ -566,11 +689,13 @@ template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' - // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. - static bool Register(const char* prefix, const char* case_name, - const char* test_names, int index) { + static bool Register(const char* prefix, const CodeLocation& code_location, + const char* case_name, const char* test_names, int index, + const std::vector& type_names = + GenerateNames()) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; @@ -578,19 +703,27 @@ class TypeParameterizedTest { // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( - (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" - + StreamableToString(index)).c_str(), - GetPrefixUntilComma(test_names).c_str(), + (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + + "/" + type_names[static_cast(index)]) + .c_str(), + StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), GetTypeName().c_str(), - NULL, // No value parameter. - GetTypeId(), - TestClass::SetUpTestCase, - TestClass::TearDownTestCase, + nullptr, // No value parameter. + code_location, GetTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite( + code_location.file.c_str(), code_location.line), + SuiteApiResolver::GetTearDownCaseOrSuite( + code_location.file.c_str(), code_location.line), new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. - return TypeParameterizedTest - ::Register(prefix, case_name, test_names, index + 1); + return TypeParameterizedTest::Register(prefix, + code_location, + case_name, + test_names, + index + 1, + type_names); } }; @@ -598,39 +731,63 @@ class TypeParameterizedTest { template class TypeParameterizedTest { public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/, int /*index*/) { + static bool Register(const char* /*prefix*/, const CodeLocation&, + const char* /*case_name*/, const char* /*test_names*/, + int /*index*/, + const std::vector& = + std::vector() /*type_names*/) { return true; } }; -// TypeParameterizedTestCase::Register() +// TypeParameterizedTestSuite::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template -class TypeParameterizedTestCase { +class TypeParameterizedTestSuite { public: - static bool Register(const char* prefix, const char* case_name, - const char* test_names) { + static bool Register(const char* prefix, CodeLocation code_location, + const TypedTestSuitePState* state, const char* case_name, + const char* test_names, + const std::vector& type_names = + GenerateNames()) { + std::string test_name = StripTrailingSpaces( + GetPrefixUntilComma(test_names)); + if (!state->TestExists(test_name)) { + fprintf(stderr, "Failed to get code location for test %s.%s at %s.", + case_name, test_name.c_str(), + FormatFileLocation(code_location.file.c_str(), + code_location.line).c_str()); + fflush(stderr); + posix::Abort(); + } + const CodeLocation& test_location = state->GetCodeLocation(test_name); + typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( - prefix, case_name, test_names, 0); + prefix, test_location, case_name, test_names, 0, type_names); // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase - ::Register(prefix, case_name, SkipComma(test_names)); + return TypeParameterizedTestSuite::Register(prefix, code_location, + state, case_name, + SkipComma(test_names), + type_names); } }; // The base case for the compile time recursion. template -class TypeParameterizedTestCase { +class TypeParameterizedTestSuite { public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/) { + static bool Register(const char* /*prefix*/, const CodeLocation&, + const TypedTestSuitePState* /*state*/, + const char* /*case_name*/, const char* /*test_names*/, + const std::vector& = + std::vector() /*type_names*/) { return true; } }; @@ -690,150 +847,16 @@ class GTEST_API_ Random { GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; -// Defining a variable of type CompileAssertTypesEqual will cause a -// compiler error iff T1 and T2 are different types. -template -struct CompileAssertTypesEqual; - -template -struct CompileAssertTypesEqual { -}; - -// Removes the reference from a type if it is a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::remove_reference, which is not widely available yet. -template -struct RemoveReference { typedef T type; }; // NOLINT -template -struct RemoveReference { typedef T type; }; // NOLINT - -// A handy wrapper around RemoveReference that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_REFERENCE_(T) \ - typename ::testing::internal::RemoveReference::type - -// Removes const from a type if it is a const type, otherwise leaves -// it unchanged. This is the same as tr1::remove_const, which is not -// widely available yet. -template -struct RemoveConst { typedef T type; }; // NOLINT -template -struct RemoveConst { typedef T type; }; // NOLINT - -// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above -// definition to fail to remove the const in 'const int[3]' and 'const -// char[3][4]'. The following specialization works around the bug. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; - -#if defined(_MSC_VER) && _MSC_VER < 1400 -// This is the only specialization that allows VC++ 7.1 to remove const in -// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC -// and thus needs to be conditionally compiled. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; -#endif - -// A handy wrapper around RemoveConst that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_CONST_(T) \ - typename ::testing::internal::RemoveConst::type - // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ - GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) - -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template -struct AddReference { typedef T& type; }; // NOLINT -template -struct AddReference { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GTEST_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference::type - -// Adds a reference to const on top of T as necessary. For example, -// it transforms -// -// char ==> const char& -// const char ==> const char& -// char& ==> const char& -// const char& ==> const char& -// -// The argument T must depend on some template parameters. -#define GTEST_REFERENCE_TO_CONST_(T) \ - GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) - -// ImplicitlyConvertible::value is a compile-time bool -// constant that's true iff type From can be implicitly converted to -// type To. -template -class ImplicitlyConvertible { - private: - // We need the following helper functions only for their types. - // They have no implementations. - - // MakeFrom() is an expression whose type is From. We cannot simply - // use From(), as the type From may not have a public default - // constructor. - static From MakeFrom(); - - // These two functions are overloaded. Given an expression - // Helper(x), the compiler will pick the first version if x can be - // implicitly converted to type To; otherwise it will pick the - // second version. - // - // The first version returns a value of size 1, and the second - // version returns a value of size 2. Therefore, by checking the - // size of Helper(x), which can be done at compile time, we can tell - // which version of Helper() is used, and hence whether x can be - // implicitly converted to type To. - static char Helper(To); - static char (&Helper(...))[2]; // NOLINT - - // We have to put the 'public' section after the 'private' section, - // or MSVC refuses to compile the code. - public: - // MSVC warns about implicitly converting from double to int for - // possible loss of data, so we need to temporarily disable the - // warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4244) // Temporarily disables warning 4244. - - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -# pragma warning(pop) // Restores the warning state. -#elif defined(__BORLANDC__) - // C++Builder cannot use member overload resolution during template - // instantiation. The simplest workaround is to use its C++0x type traits - // functions (C++Builder 2009 and above only). - static const bool value = __is_convertible(From, To); -#else - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -#endif // _MSV_VER -}; -template -const bool ImplicitlyConvertible::value; + typename std::remove_const::type>::type // IsAProtocolMessage::value is a compile-time bool constant that's -// true iff T is type ProtocolMessage, proto2::Message, or a subclass -// of those. +// true if and only if T is type proto2::Message or a subclass of it. template struct IsAProtocolMessage : public bool_constant< - ImplicitlyConvertible::value || - ImplicitlyConvertible::value> { -}; + std::is_convertible::value> {}; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest @@ -846,8 +869,11 @@ struct IsAProtocolMessage // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // -// Note that we look for both C::iterator and C::const_iterator. The -// reason is that C++ injects the name of a class as a member of the +// In C++11 mode we check the existence of a const_iterator and that an +// iterator is properly implemented for the container. +// +// For pre-C++11 that we look for both C::iterator and C::const_iterator. +// The reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named @@ -857,10 +883,13 @@ struct IsAProtocolMessage // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; -template -IsContainer IsContainerTest(int /* dummy */, - typename C::iterator* /* it */ = NULL, - typename C::const_iterator* /* const_it */ = NULL) { +template ().begin()), + class = decltype(::std::declval().end()), + class = decltype(++::std::declval()), + class = decltype(*::std::declval()), + class = typename C::const_iterator> +IsContainer IsContainerTest(int /* dummy */) { return 0; } @@ -868,12 +897,55 @@ typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } -// EnableIf::type is void when 'Cond' is true, and -// undefined when 'Cond' is false. To use SFINAE to make a function -// overload only apply when a particular expression is true, add -// "typename EnableIf::type* = 0" as the last parameter. -template struct EnableIf; -template<> struct EnableIf { typedef void type; }; // NOLINT +// Trait to detect whether a type T is a hash table. +// The heuristic used is that the type contains an inner type `hasher` and does +// not contain an inner type `reverse_iterator`. +// If the container is iterable in reverse, then order might actually matter. +template +struct IsHashTable { + private: + template + static char test(typename U::hasher*, typename U::reverse_iterator*); + template + static int test(typename U::hasher*, ...); + template + static char test(...); + + public: + static const bool value = sizeof(test(nullptr, nullptr)) == sizeof(int); +}; + +template +const bool IsHashTable::value; + +template (0)) == sizeof(IsContainer)> +struct IsRecursiveContainerImpl; + +template +struct IsRecursiveContainerImpl : public std::false_type {}; + +// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to +// obey the same inconsistencies as the IsContainerTest, namely check if +// something is a container is relying on only const_iterator in C++11 and +// is relying on both const_iterator and iterator otherwise +template +struct IsRecursiveContainerImpl { + using value_type = decltype(*std::declval()); + using type = + std::is_same::type>::type, + C>; +}; + +// IsRecursiveContainer is a unary compile-time predicate that +// evaluates whether C is a recursive container type. A recursive container +// type is a container type whose value_type is equal to the container type +// itself. An example for a recursive container type is +// boost::filesystem::path, whose iterator has a value_type that is equal to +// boost::filesystem::path. +template +struct IsRecursiveContainer : public IsRecursiveContainerImpl::type {}; // Utilities for native arrays. @@ -946,11 +1018,10 @@ void CopyArray(const T* from, size_t size, U* to) { // The relation between an NativeArray object (see below) and the // native array it represents. -enum RelationToSource { - kReference, // The NativeArray references the native array. - kCopy // The NativeArray makes a copy of the native array and - // owns the copy. -}; +// We use 2 different structs to allow non-copyable types to be used, as long +// as RelationToSourceReference() is passed. +struct RelationToSourceReference {}; +struct RelationToSourceCopy {}; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements @@ -968,22 +1039,23 @@ class NativeArray { typedef Element* iterator; typedef const Element* const_iterator; - // Constructs from a native array. - NativeArray(const Element* array, size_t count, RelationToSource relation) { - Init(array, count, relation); + // Constructs from a native array. References the source. + NativeArray(const Element* array, size_t count, RelationToSourceReference) { + InitRef(array, count); + } + + // Constructs from a native array. Copies the source. + NativeArray(const Element* array, size_t count, RelationToSourceCopy) { + InitCopy(array, count); } // Copy constructor. NativeArray(const NativeArray& rhs) { - Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + (this->*rhs.clone_)(rhs.array_, rhs.size_); } ~NativeArray() { - // Ensures that the user doesn't instantiate NativeArray with a - // const or reference type. - static_cast(StaticAssertTypeEqHelper()); - if (relation_to_source_ == kCopy) + if (clone_ != &NativeArray::InitRef) delete[] array_; } @@ -997,27 +1069,166 @@ class NativeArray { } private: - // Initializes this object; makes a copy of the input array if - // 'relation' is kCopy. - void Init(const Element* array, size_t a_size, RelationToSource relation) { - if (relation == kReference) { - array_ = array; - } else { - Element* const copy = new Element[a_size]; - CopyArray(array, a_size, copy); - array_ = copy; - } + static_assert(!std::is_const::value, "Type must not be const"); + static_assert(!std::is_reference::value, + "Type must not be a reference"); + + // Initializes this object with a copy of the input. + void InitCopy(const Element* array, size_t a_size) { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + size_ = a_size; + clone_ = &NativeArray::InitCopy; + } + + // Initializes this object with a reference of the input. + void InitRef(const Element* array, size_t a_size) { + array_ = array; size_ = a_size; - relation_to_source_ = relation; + clone_ = &NativeArray::InitRef; } const Element* array_; size_t size_; - RelationToSource relation_to_source_; + void (NativeArray::*clone_)(const Element*, size_t); GTEST_DISALLOW_ASSIGN_(NativeArray); }; +// Backport of std::index_sequence. +template +struct IndexSequence { + using type = IndexSequence; +}; + +// Double the IndexSequence, and one if plus_one is true. +template +struct DoubleSequence; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; + +// Backport of std::make_index_sequence. +// It uses O(ln(N)) instantiation depth. +template +struct MakeIndexSequence + : DoubleSequence::type, + N / 2>::type {}; + +template <> +struct MakeIndexSequence<0> : IndexSequence<> {}; + +// FIXME: This implementation of ElemFromList is O(1) in instantiation depth, +// but it is O(N^2) in total instantiations. Not sure if this is the best +// tradeoff, as it will make it somewhat slow to compile. +template +struct ElemFromListImpl {}; + +template +struct ElemFromListImpl { + using type = T; +}; + +// Get the Nth element from T... +// It uses O(1) instantiation depth. +template +struct ElemFromList; + +template +struct ElemFromList, T...> + : ElemFromListImpl... {}; + +template +class FlatTuple; + +template +struct FlatTupleElemBase; + +template +struct FlatTupleElemBase, I> { + using value_type = + typename ElemFromList::type, + T...>::type; + FlatTupleElemBase() = default; + explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {} + value_type value; +}; + +template +struct FlatTupleBase; + +template +struct FlatTupleBase, IndexSequence> + : FlatTupleElemBase, Idx>... { + using Indices = IndexSequence; + FlatTupleBase() = default; + explicit FlatTupleBase(T... t) + : FlatTupleElemBase, Idx>(std::move(t))... {} +}; + +// Analog to std::tuple but with different tradeoffs. +// This class minimizes the template instantiation depth, thus allowing more +// elements that std::tuple would. std::tuple has been seen to require an +// instantiation depth of more than 10x the number of elements in some +// implementations. +// FlatTuple and ElemFromList are not recursive and have a fixed depth +// regardless of T... +// MakeIndexSequence, on the other hand, it is recursive but with an +// instantiation depth of O(ln(N)). +template +class FlatTuple + : private FlatTupleBase, + typename MakeIndexSequence::type> { + using Indices = typename FlatTuple::FlatTupleBase::Indices; + + public: + FlatTuple() = default; + explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {} + + template + const typename ElemFromList::type& Get() const { + return static_cast*>(this)->value; + } + + template + typename ElemFromList::type& Get() { + return static_cast*>(this)->value; + } +}; + +// Utility functions to be called with static_assert to induce deprecation +// warnings. +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TEST_SUITE_P") +constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE_P is deprecated, please use " + "TYPED_TEST_SUITE_P") +constexpr bool TypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE is deprecated, please use " + "TYPED_TEST_SUITE") +constexpr bool TypedTestCaseIsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "REGISTER_TYPED_TEST_CASE_P is deprecated, please use " + "REGISTER_TYPED_TEST_SUITE_P") +constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TYPED_TEST_SUITE_P") +constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } + } // namespace internal } // namespace testing @@ -1037,7 +1248,10 @@ class NativeArray { #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) -// Suppresses MSVC warnings 4072 (unreachable code) for the code following +#define GTEST_SKIP_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip) + +// Suppress MSVC warning 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ @@ -1129,30 +1343,38 @@ class NativeArray { " Actual: it does.") // Expands to the name of the class that implements the given test. -#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - test_case_name##_##test_name##_Test +#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + test_suite_name##_##test_name##_Test // Helper macro for defining tests. -#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ -class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ - public:\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ - private:\ - virtual void TestBody();\ - static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ -};\ -\ -::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ - ::test_info_ =\ - ::testing::internal::MakeAndRegisterTestInfo(\ - #test_case_name, #test_name, NULL, NULL, \ - (parent_id), \ - parent_class::SetUpTestCase, \ - parent_class::TearDownTestCase, \ - new ::testing::internal::TestFactoryImpl<\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ -void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() +#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \ + static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \ + "test_suite_name must not be empty"); \ + static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \ + "test_name must not be empty"); \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public parent_class { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + \ + private: \ + virtual void TestBody(); \ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + \ + ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::test_info_ = \ + ::testing::internal::MakeAndRegisterTestInfo( \ + #test_suite_name, #test_name, nullptr, nullptr, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \ + new ::testing::internal::TestFactoryImpl); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/test/gtest/include/gtest/internal/gtest-linked_ptr.h b/test/gtest/include/gtest/internal/gtest-linked_ptr.h index b1362cd002..3602942217 100644 --- a/test/gtest/include/gtest/internal/gtest-linked_ptr.h +++ b/test/gtest/include/gtest/internal/gtest-linked_ptr.h @@ -110,7 +110,12 @@ class linked_ptr_internal { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; - while (p->next_ != ptr) p = p->next_; + while (p->next_ != ptr) { + assert(p->next_ != this && + "Trying to join() a linked ring we are already in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } p->next_ = this; next_ = ptr; } @@ -123,7 +128,12 @@ class linked_ptr_internal { if (next_ == this) return true; linked_ptr_internal const* p = next_; - while (p->next_ != this) p = p->next_; + while (p->next_ != this) { + assert(p->next_ != next_ && + "Trying to depart() a linked ring we are not in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } p->next_ = next_; return false; } diff --git a/test/gtest/include/gtest/internal/gtest-param-util-generated.h b/test/gtest/include/gtest/internal/gtest-param-util-generated.h index e80548592c..dcf90c279a 100644 --- a/test/gtest/include/gtest/internal/gtest-param-util-generated.h +++ b/test/gtest/include/gtest/internal/gtest-param-util-generated.h @@ -40,20 +40,15 @@ // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is +// by the maximum arity of the implementation of tuple which is // currently set at 10. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Forward declarations of ValuesIn(), which is implemented in @@ -79,7 +74,10 @@ class ValueArray1 { explicit ValueArray1(T1 v1) : v1_(v1) {} template - operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + operator ParamGenerator() const { + const T array[] = {static_cast(v1_)}; + return ValuesIn(array); + } private: // No implementation - assignment is unsupported. @@ -3157,9 +3155,9 @@ class ValueArray50 { // template class CartesianProductGenerator2 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) @@ -3205,7 +3203,7 @@ class CartesianProductGenerator2 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3237,7 +3235,7 @@ class CartesianProductGenerator2 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_); + current_value_.reset(new ParamType(*current1_, *current2_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3259,7 +3257,7 @@ class CartesianProductGenerator2 const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. @@ -3272,9 +3270,9 @@ class CartesianProductGenerator2 template class CartesianProductGenerator3 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) @@ -3328,7 +3326,7 @@ class CartesianProductGenerator3 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3364,7 +3362,7 @@ class CartesianProductGenerator3 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3390,7 +3388,7 @@ class CartesianProductGenerator3 const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. @@ -3404,9 +3402,9 @@ class CartesianProductGenerator3 template class CartesianProductGenerator4 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3469,7 +3467,7 @@ class CartesianProductGenerator4 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3509,8 +3507,8 @@ class CartesianProductGenerator4 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3540,7 +3538,7 @@ class CartesianProductGenerator4 const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. @@ -3555,9 +3553,9 @@ class CartesianProductGenerator4 template class CartesianProductGenerator5 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3627,7 +3625,7 @@ class CartesianProductGenerator5 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3671,8 +3669,8 @@ class CartesianProductGenerator5 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3706,7 +3704,7 @@ class CartesianProductGenerator5 const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. @@ -3723,10 +3721,10 @@ class CartesianProductGenerator5 template class CartesianProductGenerator6 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3804,7 +3802,7 @@ class CartesianProductGenerator6 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3852,8 +3850,8 @@ class CartesianProductGenerator6 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3891,7 +3889,7 @@ class CartesianProductGenerator6 const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. @@ -3909,10 +3907,10 @@ class CartesianProductGenerator6 template class CartesianProductGenerator7 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3998,7 +3996,7 @@ class CartesianProductGenerator7 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4050,8 +4048,8 @@ class CartesianProductGenerator7 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4093,7 +4091,7 @@ class CartesianProductGenerator7 const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. @@ -4112,10 +4110,10 @@ class CartesianProductGenerator7 template class CartesianProductGenerator8 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4211,7 +4209,7 @@ class CartesianProductGenerator8 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4267,8 +4265,8 @@ class CartesianProductGenerator8 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4314,7 +4312,7 @@ class CartesianProductGenerator8 const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. @@ -4334,10 +4332,10 @@ class CartesianProductGenerator8 template class CartesianProductGenerator9 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4440,7 +4438,7 @@ class CartesianProductGenerator9 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4500,9 +4498,9 @@ class CartesianProductGenerator9 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_); + *current9_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4552,7 +4550,7 @@ class CartesianProductGenerator9 const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. @@ -4573,10 +4571,10 @@ class CartesianProductGenerator9 template class CartesianProductGenerator10 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4687,7 +4685,7 @@ class CartesianProductGenerator10 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4751,9 +4749,9 @@ class CartesianProductGenerator10 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_, *current10_); + *current9_, *current10_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4807,7 +4805,7 @@ class CartesianProductGenerator10 const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. @@ -4838,8 +4836,8 @@ class CartesianProductHolder2 { CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); @@ -4860,8 +4858,8 @@ CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), @@ -4885,8 +4883,8 @@ CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), @@ -4912,8 +4910,8 @@ CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), @@ -4943,8 +4941,8 @@ CartesianProductHolder6(const Generator1& g1, const Generator2& g2, : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), @@ -4976,9 +4974,9 @@ CartesianProductHolder7(const Generator1& g1, const Generator2& g2, : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), @@ -5014,9 +5012,9 @@ CartesianProductHolder8(const Generator1& g1, const Generator2& g2, g8_(g8) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), @@ -5055,9 +5053,9 @@ CartesianProductHolder9(const Generator1& g1, const Generator2& g2, g9_(g9) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), @@ -5099,10 +5097,10 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, g9_(g9), g10_(g10) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator10( static_cast >(g1_), @@ -5138,6 +5136,4 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/test/gtest/include/gtest/internal/gtest-param-util-generated.h.pump b/test/gtest/include/gtest/internal/gtest-param-util-generated.h.pump index 009206fd31..d65086a01e 100644 --- a/test/gtest/include/gtest/internal/gtest-param-util-generated.h.pump +++ b/test/gtest/include/gtest/internal/gtest-param-util-generated.h.pump @@ -39,20 +39,15 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // and at most $maxtuple arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is +// by the maximum arity of the implementation of tuple which is // currently set at $maxtuple. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Forward declarations of ValuesIn(), which is implemented in @@ -72,29 +67,14 @@ internal::ParamGenerator ValuesIn( namespace internal { // Used in the Values() function to provide polymorphic capabilities. -template -class ValueArray1 { - public: - explicit ValueArray1(T1 v1) : v1_(v1) {} - - template - operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray1& other); - - const T1 v1_; -}; - -$range i 2..n +$range i 1..n $for i [[ $range j 1..i template <$for j, [[typename T$j]]> class ValueArray$i { public: - ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} + $if i==1 [[explicit ]]ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} template operator ParamGenerator() const { @@ -128,9 +108,9 @@ $range k 2..i template <$for j, [[typename T$j]]> class CartesianProductGenerator$i - : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > { + : public ParamGeneratorInterface< ::testing::tuple<$for j, [[T$j]]> > { public: - typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType; + typedef ::testing::tuple<$for j, [[T$j]]> ParamType; CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) : $for j, [[g$(j)_(g$j)]] {} @@ -180,7 +160,7 @@ $for k [[ virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -212,7 +192,7 @@ $for k [[ void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType($for j, [[*current$(j)_]]); + current_value_.reset(new ParamType($for j, [[*current$(j)_]])); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -237,7 +217,7 @@ $for j [[ typename ParamGenerator::iterator current$(j)_; ]] - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator$i::Iterator // No implementation - assignment is unsupported. @@ -269,8 +249,8 @@ class CartesianProductHolder$i { CartesianProductHolder$i($for j, [[const Generator$j& g$j]]) : $for j, [[g$(j)_(g$j)]] {} template <$for j, [[typename T$j]]> - operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const { - return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >( + operator ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >() const { + return ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >( new CartesianProductGenerator$i<$for j, [[T$j]]>( $for j,[[ @@ -296,6 +276,4 @@ $for j [[ } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/test/gtest/include/gtest/internal/gtest-param-util.h b/test/gtest/include/gtest/internal/gtest-param-util.h index d5e1028b0c..97533993c0 100644 --- a/test/gtest/include/gtest/internal/gtest-param-util.h +++ b/test/gtest/include/gtest/internal/gtest-param-util.h @@ -26,39 +26,61 @@ // 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. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#include + +#include #include +#include +#include +#include #include #include -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-linked_ptr.h" #include "gtest/internal/gtest-port.h" #include "gtest/gtest-printers.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { +// Input to a parameterized test name generator, describing a test parameter. +// Consists of the parameter value and the integer parameter index. +template +struct TestParamInfo { + TestParamInfo(const ParamType& a_param, size_t an_index) : + param(a_param), + index(an_index) {} + ParamType param; + size_t index; +}; + +// A builtin parameterized test name generator which returns the result of +// testing::PrintToString. +struct PrintToStringParamName { + template + std::string operator()(const TestParamInfo& info) const { + return PrintToString(info.param); + } +}; + namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// +// Utility Functions + // Outputs a message explaining invalid registration of different -// fixture class for the same test case. This may happen when +// fixture class for the same test suite. This may happen when // TEST_P macro is used to define two tests with the same name // but in different namespaces. -GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line); +GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name, + CodeLocation code_location); template class ParamGeneratorInterface; template class ParamGenerator; @@ -133,7 +155,7 @@ class ParamIterator { private: friend class ParamGenerator; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} - scoped_ptr > impl_; + std::unique_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators @@ -172,7 +194,7 @@ class ParamGenerator { iterator end() const { return iterator(impl_->End()); } private: - linked_ptr > impl_; + std::shared_ptr > impl_; }; // Generates values from a range of two comparable values. Can be used to @@ -185,12 +207,12 @@ class RangeGenerator : public ParamGeneratorInterface { RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} - virtual ~RangeGenerator() {} + ~RangeGenerator() override {} - virtual ParamIteratorInterface* Begin() const { + ParamIteratorInterface* Begin() const override { return new Iterator(this, begin_, 0, step_); } - virtual ParamIteratorInterface* End() const { + ParamIteratorInterface* End() const override { return new Iterator(this, end_, end_index_, step_); } @@ -200,20 +222,20 @@ class RangeGenerator : public ParamGeneratorInterface { Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} - virtual ~Iterator() {} + ~Iterator() override {} - virtual const ParamGeneratorInterface* BaseGenerator() const { + const ParamGeneratorInterface* BaseGenerator() const override { return base_; } - virtual void Advance() { - value_ = value_ + step_; + void Advance() override { + value_ = static_cast(value_ + step_); index_++; } - virtual ParamIteratorInterface* Clone() const { + ParamIteratorInterface* Clone() const override { return new Iterator(*this); } - virtual const T* Current() const { return &value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { + const T* Current() const override { return &value_; } + bool Equals(const ParamIteratorInterface& other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) @@ -243,7 +265,7 @@ class RangeGenerator : public ParamGeneratorInterface { const T& end, const IncrementT& step) { int end_index = 0; - for (T i = begin; i < end; i = i + step) + for (T i = begin; i < end; i = static_cast(i + step)) end_index++; return end_index; } @@ -270,12 +292,12 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} - virtual ~ValuesInIteratorRangeGenerator() {} + ~ValuesInIteratorRangeGenerator() override {} - virtual ParamIteratorInterface* Begin() const { + ParamIteratorInterface* Begin() const override { return new Iterator(this, container_.begin()); } - virtual ParamIteratorInterface* End() const { + ParamIteratorInterface* End() const override { return new Iterator(this, container_.end()); } @@ -287,16 +309,16 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} - virtual ~Iterator() {} + ~Iterator() override {} - virtual const ParamGeneratorInterface* BaseGenerator() const { + const ParamGeneratorInterface* BaseGenerator() const override { return base_; } - virtual void Advance() { + void Advance() override { ++iterator_; value_.reset(); } - virtual ParamIteratorInterface* Clone() const { + ParamIteratorInterface* Clone() const override { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ @@ -306,12 +328,11 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. - virtual const T* Current() const { - if (value_.get() == NULL) - value_.reset(new T(*iterator_)); + const T* Current() const override { + if (value_.get() == nullptr) value_.reset(new T(*iterator_)); return value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { + bool Equals(const ParamIteratorInterface& other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) @@ -334,9 +355,9 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { // A cached value of *iterator_. We keep it here to allow access by // pointer in the wrapping iterator's operator->(). // value_ needs to be mutable to be accessed in Current(). - // Use of scoped_ptr helps manage cached value's lifetime, + // Use of std::unique_ptr helps manage cached value's lifetime, // which is bound by the lifespan of the iterator itself. - mutable scoped_ptr value_; + mutable std::unique_ptr value_; }; // class ValuesInIteratorRangeGenerator::Iterator // No implementation - assignment is unsupported. @@ -345,6 +366,24 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { const ContainerType container_; }; // class ValuesInIteratorRangeGenerator +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Default parameterized test name generator, returns a string containing the +// integer test parameter index. +template +std::string DefaultParamName(const TestParamInfo& info) { + Message name_stream; + name_stream << info.index; + return name_stream.GetString(); +} + +template +void TestNotEmpty() { + static_assert(sizeof(T) == 0, "Empty arguments are not allowed."); +} +template +void TestNotEmpty(const T&) {} + // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Stores a parameter value and later creates tests parameterized with that @@ -355,7 +394,7 @@ class ParameterizedTestFactory : public TestFactoryBase { typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} - virtual Test* CreateTest() { + Test* CreateTest() override { TestClass::SetParam(¶meter_); return new TestClass(); } @@ -383,19 +422,19 @@ class TestMetaFactoryBase { // TestMetaFactory creates test factories for passing into // MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives // ownership of test factory pointer, same factory object cannot be passed -// into that method twice. But ParameterizedTestCaseInfo is going to call +// into that method twice. But ParameterizedTestSuiteInfo is going to call // it for each Test/Parameter value combination. Thus it needs meta factory // creator class. -template +template class TestMetaFactory - : public TestMetaFactoryBase { + : public TestMetaFactoryBase { public: - typedef typename TestCase::ParamType ParamType; + using ParamType = typename TestSuite::ParamType; TestMetaFactory() {} - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { - return new ParameterizedTestFactory(parameter); + TestFactoryBase* CreateTestFactory(ParamType parameter) override { + return new ParameterizedTestFactory(parameter); } private: @@ -404,216 +443,441 @@ class TestMetaFactory // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseInfoBase is a generic interface -// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// ParameterizedTestSuiteInfoBase is a generic interface +// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase // accumulates test information provided by TEST_P macro invocations -// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations // and uses that information to register all resulting test instances -// in RegisterTests method. The ParameterizeTestCaseRegistry class holds -// a collection of pointers to the ParameterizedTestCaseInfo objects +// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds +// a collection of pointers to the ParameterizedTestSuiteInfo objects // and calls RegisterTests() on each of them when asked. -class ParameterizedTestCaseInfoBase { +class ParameterizedTestSuiteInfoBase { public: - virtual ~ParameterizedTestCaseInfoBase() {} + virtual ~ParameterizedTestSuiteInfoBase() {} - // Base part of test case name for display purposes. - virtual const string& GetTestCaseName() const = 0; + // Base part of test suite name for display purposes. + virtual const std::string& GetTestSuiteName() const = 0; // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const = 0; + virtual TypeId GetTestSuiteTypeId() const = 0; // UnitTest class invokes this method to register tests in this - // test case right before running them in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. + // test suite right before running them in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. virtual void RegisterTests() = 0; protected: - ParameterizedTestCaseInfoBase() {} + ParameterizedTestSuiteInfoBase() {} private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P -// macro invocations for a particular test case and generators -// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that -// test case. It registers tests with all values generated by all +// ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test suite and generators +// obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that +// test suite. It registers tests with all values generated by all // generators when asked. -template -class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { +template +class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { public: // ParamType and GeneratorCreationFunc are private types but are required // for declarations of public methods AddTestPattern() and - // AddTestCaseInstantiation(). - typedef typename TestCase::ParamType ParamType; + // AddTestSuiteInstantiation(). + using ParamType = typename TestSuite::ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator(GeneratorCreationFunc)(); + using ParamNameGeneratorFunc = std::string(const TestParamInfo&); - explicit ParameterizedTestCaseInfo(const char* name) - : test_case_name_(name) {} + explicit ParameterizedTestSuiteInfo(const char* name, + CodeLocation code_location) + : test_suite_name_(name), code_location_(code_location) {} // Test case base name for display purposes. - virtual const string& GetTestCaseName() const { return test_case_name_; } + const std::string& GetTestSuiteName() const override { + return test_suite_name_; + } // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + TypeId GetTestSuiteTypeId() const override { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. - // test_case_name is the base name of the test case (without invocation + // test_suite_name is the base name of the test suite (without invocation // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is - // test case base name and DoBar is test base name. - void AddTestPattern(const char* test_case_name, - const char* test_base_name, + // test suite base name and DoBar is test base name. + void AddTestPattern(const char* test_suite_name, const char* test_base_name, TestMetaFactoryBase* meta_factory) { - tests_.push_back(linked_ptr(new TestInfo(test_case_name, - test_base_name, - meta_factory))); + tests_.push_back(std::shared_ptr( + new TestInfo(test_suite_name, test_base_name, meta_factory))); } - // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information // about a generator. - int AddTestCaseInstantiation(const string& instantiation_name, - GeneratorCreationFunc* func, - const char* /* file */, - int /* line */) { - instantiations_.push_back(::std::make_pair(instantiation_name, func)); + int AddTestSuiteInstantiation(const std::string& instantiation_name, + GeneratorCreationFunc* func, + ParamNameGeneratorFunc* name_func, + const char* file, int line) { + instantiations_.push_back( + InstantiationInfo(instantiation_name, func, name_func, file, line)); return 0; // Return value used only to run this method in namespace scope. } - // UnitTest class invokes this method to register tests in this test case - // test cases right before running tests in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - // UnitTest has a guard to prevent from calling this method more then once. - virtual void RegisterTests() { + // UnitTest class invokes this method to register tests in this test suite + // test suites right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more than once. + void RegisterTests() override { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { - linked_ptr test_info = *test_it; + std::shared_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { - const string& instantiation_name = gen_it->first; - ParamGenerator generator((*gen_it->second)()); + const std::string& instantiation_name = gen_it->name; + ParamGenerator generator((*gen_it->generator)()); + ParamNameGeneratorFunc* name_func = gen_it->name_func; + const char* file = gen_it->file; + int line = gen_it->line; - string test_case_name; + std::string test_suite_name; if ( !instantiation_name.empty() ) - test_case_name = instantiation_name + "/"; - test_case_name += test_info->test_case_base_name; + test_suite_name = instantiation_name + "/"; + test_suite_name += test_info->test_suite_base_name; - int i = 0; + size_t i = 0; + std::set test_param_names; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; - test_name_stream << test_info->test_base_name << "/" << i; + + std::string param_name = name_func( + TestParamInfo(*param_it, i)); + + GTEST_CHECK_(IsValidParamName(param_name)) + << "Parameterized test name '" << param_name + << "' is invalid, in " << file + << " line " << line << std::endl; + + GTEST_CHECK_(test_param_names.count(param_name) == 0) + << "Duplicate parameterized test name '" << param_name + << "', in " << file << " line " << line << std::endl; + + test_param_names.insert(param_name); + + if (!test_info->test_base_name.empty()) { + test_name_stream << test_info->test_base_name << "/"; + } + test_name_stream << param_name; MakeAndRegisterTestInfo( - test_case_name.c_str(), - test_name_stream.GetString().c_str(), - NULL, // No type parameter. - PrintToString(*param_it).c_str(), - GetTestCaseTypeId(), - TestCase::SetUpTestCase, - TestCase::TearDownTestCase, + test_suite_name.c_str(), test_name_stream.GetString().c_str(), + nullptr, // No type parameter. + PrintToString(*param_it).c_str(), code_location_, + GetTestSuiteTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + SuiteApiResolver::GetTearDownCaseOrSuite(file, line), test_info->test_meta_factory->CreateTestFactory(*param_it)); } // for param_it } // for gen_it } // for test_it - } // RegisterTests + } // RegisterTests private: // LocalTestInfo structure keeps information about a single test registered // with TEST_P macro. struct TestInfo { - TestInfo(const char* a_test_case_base_name, - const char* a_test_base_name, - TestMetaFactoryBase* a_test_meta_factory) : - test_case_base_name(a_test_case_base_name), - test_base_name(a_test_base_name), - test_meta_factory(a_test_meta_factory) {} - - const string test_case_base_name; - const string test_base_name; - const scoped_ptr > test_meta_factory; + TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) + : test_suite_base_name(a_test_suite_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const std::string test_suite_base_name; + const std::string test_base_name; + const std::unique_ptr > test_meta_factory; + }; + using TestInfoContainer = ::std::vector >; + // Records data received from INSTANTIATE_TEST_SUITE_P macros: + // + struct InstantiationInfo { + InstantiationInfo(const std::string &name_in, + GeneratorCreationFunc* generator_in, + ParamNameGeneratorFunc* name_func_in, + const char* file_in, + int line_in) + : name(name_in), + generator(generator_in), + name_func(name_func_in), + file(file_in), + line(line_in) {} + + std::string name; + GeneratorCreationFunc* generator; + ParamNameGeneratorFunc* name_func; + const char* file; + int line; }; - typedef ::std::vector > TestInfoContainer; - // Keeps pairs of - // received from INSTANTIATE_TEST_CASE_P macros. - typedef ::std::vector > - InstantiationContainer; + typedef ::std::vector InstantiationContainer; + + static bool IsValidParamName(const std::string& name) { + // Check for empty string + if (name.empty()) + return false; + + // Check for invalid characters + for (std::string::size_type index = 0; index < name.size(); ++index) { + if (!isalnum(name[index]) && name[index] != '_') + return false; + } + + return true; + } - const string test_case_name_; + const std::string test_suite_name_; + CodeLocation code_location_; TestInfoContainer tests_; InstantiationContainer instantiations_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); -}; // class ParameterizedTestCaseInfo + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo); +}; // class ParameterizedTestSuiteInfo + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +template +using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase -// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P -// macros use it to locate their corresponding ParameterizedTestCaseInfo -// descriptors. -class ParameterizedTestCaseRegistry { +// ParameterizedTestSuiteRegistry contains a map of +// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P +// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding +// ParameterizedTestSuiteInfo descriptors. +class ParameterizedTestSuiteRegistry { public: - ParameterizedTestCaseRegistry() {} - ~ParameterizedTestCaseRegistry() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - delete *it; + ParameterizedTestSuiteRegistry() {} + ~ParameterizedTestSuiteRegistry() { + for (auto& test_suite_info : test_suite_infos_) { + delete test_suite_info; } } // Looks up or creates and returns a structure containing information about - // tests and instantiations of a particular test case. - template - ParameterizedTestCaseInfo* GetTestCasePatternHolder( - const char* test_case_name, - const char* file, - int line) { - ParameterizedTestCaseInfo* typed_test_info = NULL; - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - if ((*it)->GetTestCaseName() == test_case_name) { - if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // tests and instantiations of a particular test suite. + template + ParameterizedTestSuiteInfo* GetTestSuitePatternHolder( + const char* test_suite_name, CodeLocation code_location) { + ParameterizedTestSuiteInfo* typed_test_info = nullptr; + for (auto& test_suite_info : test_suite_infos_) { + if (test_suite_info->GetTestSuiteName() == test_suite_name) { + if (test_suite_info->GetTestSuiteTypeId() != GetTypeId()) { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct - // test case setup and tear-down in this case. - ReportInvalidTestCaseType(test_case_name, file, line); + // test suite setup and tear-down in this case. + ReportInvalidTestSuiteType(test_suite_name, code_location); posix::Abort(); } else { // At this point we are sure that the object we found is of the same // type we are looking for, so we downcast it to that type // without further checks. typed_test_info = CheckedDowncastToActualType< - ParameterizedTestCaseInfo >(*it); + ParameterizedTestSuiteInfo >(test_suite_info); } break; } } - if (typed_test_info == NULL) { - typed_test_info = new ParameterizedTestCaseInfo(test_case_name); - test_case_infos_.push_back(typed_test_info); + if (typed_test_info == nullptr) { + typed_test_info = new ParameterizedTestSuiteInfo( + test_suite_name, code_location); + test_suite_infos_.push_back(typed_test_info); } return typed_test_info; } void RegisterTests() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - (*it)->RegisterTests(); + for (auto& test_suite_info : test_suite_infos_) { + test_suite_info->RegisterTests(); } } +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, CodeLocation code_location) { + return GetTestSuitePatternHolder(test_case_name, code_location); + } + +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ private: - typedef ::std::vector TestCaseInfoContainer; + using TestSuiteInfoContainer = ::std::vector; - TestCaseInfoContainer test_case_infos_; + TestSuiteInfoContainer test_suite_infos_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry); }; } // namespace internal -} // namespace testing -#endif // GTEST_HAS_PARAM_TEST +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { +// Used in the Values() function to provide polymorphic capabilities. + +template +class ValueArray { + public: + ValueArray(Ts... v) : v_{std::move(v)...} {} + + template + operator ParamGenerator() const { // NOLINT + return ValuesIn(MakeVector(MakeIndexSequence())); + } + + private: + template + std::vector MakeVector(IndexSequence) const { + return std::vector{static_cast(v_.template Get())...}; + } + + FlatTuple v_; +}; + +template +class CartesianProductGenerator + : public ParamGeneratorInterface<::std::tuple> { + public: + typedef ::std::tuple ParamType; + + CartesianProductGenerator(const std::tuple...>& g) + : generators_(g) {} + ~CartesianProductGenerator() override {} + + ParamIteratorInterface* Begin() const override { + return new Iterator(this, generators_, false); + } + ParamIteratorInterface* End() const override { + return new Iterator(this, generators_, true); + } + + private: + template + class IteratorImpl; + template + class IteratorImpl> + : public ParamIteratorInterface { + public: + IteratorImpl(const ParamGeneratorInterface* base, + const std::tuple...>& generators, bool is_end) + : base_(base), + begin_(std::get(generators).begin()...), + end_(std::get(generators).end()...), + current_(is_end ? end_ : begin_) { + ComputeCurrentValue(); + } + ~IteratorImpl() override {} + + const ParamGeneratorInterface* BaseGenerator() const override { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + void Advance() override { + assert(!AtEnd()); + // Advance the last iterator. + ++std::get(current_); + // if that reaches end, propagate that up. + AdvanceIfEnd(); + ComputeCurrentValue(); + } + ParamIteratorInterface* Clone() const override { + return new IteratorImpl(*this); + } + + const ParamType* Current() const override { return current_value_.get(); } + + bool Equals(const ParamIteratorInterface& other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const IteratorImpl* typed_other = + CheckedDowncastToActualType(&other); + + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + if (AtEnd() && typed_other->AtEnd()) return true; + + bool same = true; + bool dummy[] = { + (same = same && std::get(current_) == + std::get(typed_other->current_))...}; + (void)dummy; + return same; + } + + private: + template + void AdvanceIfEnd() { + if (std::get(current_) != std::get(end_)) return; + + bool last = ThisI == 0; + if (last) { + // We are done. Nothing else to propagate. + return; + } + + constexpr size_t NextI = ThisI - (ThisI != 0); + std::get(current_) = std::get(begin_); + ++std::get(current_); + AdvanceIfEnd(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = std::make_shared(*std::get(current_)...); + } + bool AtEnd() const { + bool at_end = false; + bool dummy[] = { + (at_end = at_end || std::get(current_) == std::get(end_))...}; + (void)dummy; + return at_end; + } + + const ParamGeneratorInterface* const base_; + std::tuple::iterator...> begin_; + std::tuple::iterator...> end_; + std::tuple::iterator...> current_; + std::shared_ptr current_value_; + }; + + using Iterator = IteratorImpl::type>; + + std::tuple...> generators_; +}; + +template +class CartesianProductHolder { + public: + CartesianProductHolder(const Gen&... g) : generators_(g...) {} + template + operator ParamGenerator<::std::tuple>() const { + return ParamGenerator<::std::tuple>( + new CartesianProductGenerator(generators_)); + } + + private: + std::tuple generators_; +}; + +} // namespace internal +} // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ diff --git a/test/gtest/include/gtest/internal/gtest-port-arch.h b/test/gtest/include/gtest/internal/gtest-port-arch.h new file mode 100644 index 0000000000..cece93dba1 --- /dev/null +++ b/test/gtest/include/gtest/internal/gtest-port-arch.h @@ -0,0 +1,107 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the GTEST_OS_* macro. +// It is separate from gtest-port.h so that custom/gtest-port.h can include it. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +# elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) +# define GTEST_OS_WINDOWS_MINGW 1 +# define GTEST_OS_WINDOWS 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(WINAPI_FAMILY) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define GTEST_OS_WINDOWS_DESKTOP 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +# define GTEST_OS_WINDOWS_PHONE 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +# define GTEST_OS_WINDOWS_RT 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) +# define GTEST_OS_WINDOWS_PHONE 1 +# define GTEST_OS_WINDOWS_TV_TITLE 1 +# else + // WINAPI_FAMILY defined but no known partition matched. + // Default to desktop. +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __OS2__ +# define GTEST_OS_OS2 1 +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +# if TARGET_OS_IPHONE +# define GTEST_OS_IOS 1 +# endif +#elif defined __DragonFly__ +# define GTEST_OS_DRAGONFLY 1 +#elif defined __FreeBSD__ +# define GTEST_OS_FREEBSD 1 +#elif defined __Fuchsia__ +# define GTEST_OS_FUCHSIA 1 +#elif defined(__GLIBC__) && defined(__FreeBSD_kernel__) +# define GTEST_OS_GNU_KFREEBSD 1 +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# if defined __ANDROID__ +# define GTEST_OS_LINUX_ANDROID 1 +# endif +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#elif defined __NetBSD__ +# define GTEST_OS_NETBSD 1 +#elif defined __OpenBSD__ +# define GTEST_OS_OPENBSD 1 +#elif defined __QNX__ +# define GTEST_OS_QNX 1 +#elif defined(__HAIKU__) +#define GTEST_OS_HAIKU 1 +#endif // __CYGWIN__ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ diff --git a/test/gtest/include/gtest/internal/gtest-port.h b/test/gtest/include/gtest/internal/gtest-port.h index ab40df1899..063fcb1083 100644 --- a/test/gtest/include/gtest/internal/gtest-port.h +++ b/test/gtest/include/gtest/internal/gtest-port.h @@ -27,34 +27,51 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan) -// // Low-level types and utilities for porting Google Test to various -// platforms. They are subject to change without notice. DO NOT USE -// THEM IN USER CODE. +// platforms. All macros ending with _ and symbols defined in an +// internal namespace are subject to change without notice. Code +// outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't +// end with _ are part of Google Test's public API and can be used by +// code outside Google Test. // // This file is fundamental to Google Test. All other Google Test source // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -#pragma GCC system_header -// The user can define the following macros in the build script to -// control Google Test's behavior. If the user doesn't define a macro -// in this list, Google Test will define it. +// Environment-describing macros +// ----------------------------- +// +// Google Test can be used in many different environments. Macros in +// this section tell Google Test what kind of environment it is being +// used in, such that Google Test can provide environment-specific +// features and implementations. +// +// Google Test tries to automatically detect the properties of its +// environment, so users usually don't need to worry about these +// macros. However, the automatic detection is not perfect. +// Sometimes it's necessary for a user to define some of the following +// macros in the build script to override Google Test's decisions. +// +// If the user doesn't define a macro in the list, Google Test will +// provide a default definition. After this header is #included, all +// macros in this list will be defined to either 1 or 0. +// +// Notes to maintainers: +// - Each macro here is a user-tweakable knob; do not grow the list +// lightly. +// - Use #if to key off these macros. Don't use #ifdef or "#if +// defined(...)", which will not work as these macros are ALWAYS +// defined. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. -// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::string, which is different to std::string). -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::wstring, which is different to std::wstring). // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that @@ -64,8 +81,6 @@ // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). -// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple -// is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". @@ -73,12 +88,6 @@ // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). -// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google -// Test's own tr1 tuple implementation should be -// used. Unused when the user sets -// GTEST_HAS_TR1_TUPLE to 0. -// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test -// is building in C++11/C++98 mode. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as @@ -86,53 +95,96 @@ // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. - -// This header defines the following utilities: +// GTEST_DEFAULT_DEATH_TEST_STYLE +// - The default value of --gtest_death_test_style. +// The legacy default has been "fast" in the open +// source version since 2008. The recommended value +// is "threadsafe", and can be set in +// custom/gtest-port.h. + +// Platform-indicating macros +// -------------------------- +// +// Macros indicating the platform on which Google Test is being used +// (a macro is defined to 1 if compiled on the given platform; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. // -// Macros indicating the current platform (defined to 1 if compiled on -// the given platform; otherwise undefined): // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_DRAGONFLY - DragonFlyBSD +// GTEST_OS_FREEBSD - FreeBSD +// GTEST_OS_FUCHSIA - Fuchsia +// GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD +// GTEST_OS_HAIKU - Haiku // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS -// GTEST_OS_IOS_SIMULATOR - iOS simulator // GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_NETBSD - NetBSD // GTEST_OS_OPENBSD - OpenBSD +// GTEST_OS_OS2 - OS/2 // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris -// GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_WINDOWS_PHONE - Windows Phone +// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT // GTEST_OS_ZOS - z/OS // -// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // -// Note that it is possible that none of the GTEST_OS_* macros are defined. +// It is possible that none of the GTEST_OS_* macros are defined. + +// Feature-indicating macros +// ------------------------- +// +// Macros indicating which Google Test features are available (a macro +// is defined to 1 if the corresponding feature is supported; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. +// +// These macros are public so that portable tests can be written. +// Such tests typically surround code using a feature with an #if +// which controls that code. For example: +// +// #if GTEST_HAS_DEATH_TEST +// EXPECT_DEATH(DoSomethingDeadly()); +// #endif // -// Macros indicating available Google Test features (defined to 1 if -// the corresponding feature is supported; otherwise undefined): -// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized -// tests) // GTEST_HAS_DEATH_TEST - death tests -// GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_IS_THREADSAFE - Google Test is thread-safe. +// GOOGLETEST_CM0007 DO NOT DELETE // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; -// the above two are mutually exclusive. -// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). +// the above RE\b(s) are mutually exclusive. + +// Misc public macros +// ------------------ +// +// GTEST_FLAG(flag_name) - references the variable corresponding to +// the given Google Test flag. + +// Internal utilities +// ------------------ +// +// The following macros and utilities are for Google Test's INTERNAL +// use only. Code outside Google Test MUST NOT USE THEM DIRECTLY. // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. @@ -141,28 +193,21 @@ // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is +// suppressed (constant conditional). +// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 +// is suppressed. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() -// - synchronization primitives. -// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above -// synchronization primitives have real implementations -// and Google Test is thread-safe; or 0 otherwise. -// -// Template meta programming: -// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. -// IteratorTraits - partial implementation of std::iterator_traits, which -// is not available in libCstd when compiled with Sun C++. -// -// Smart pointers: -// scoped_ptr - as in TR2. +// - synchronization primitives. // // Regular expressions: // RE - a simple regular expression class using the POSIX -// Extended Regular Expression syntax on UNIX-like -// platforms, or a reduced regular exception syntax on -// other platforms, including Windows. -// +// Extended Regular Expression syntax on UNIX-like platforms +// GOOGLETEST_CM0008 DO NOT DELETE +// or a reduced regular exception syntax on other +// platforms, including Windows. // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. @@ -183,7 +228,6 @@ // BiggestInt - the biggest signed integer type. // // Command-line utilities: -// GTEST_FLAG() - references a flag. // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - returns the command line as a vector of strings. @@ -193,12 +237,20 @@ // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. +// +// Deprecation warnings: +// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as +// deprecated; calling a marked function +// should generate a compiler warning #include // for isspace, etc #include // for ptrdiff_t -#include #include +#include #include +#include +#include + #ifndef _WIN32_WCE # include # include @@ -209,16 +261,29 @@ # include #endif -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" -#define GTEST_FLAG_PREFIX_ "gtest_" -#define GTEST_FLAG_PREFIX_DASH_ "gtest-" -#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" -#define GTEST_NAME_ "Google Test" -#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include +#include +#include // NOLINT + +#include "gtest/internal/gtest-port-arch.h" +#include "gtest/internal/custom/gtest-port.h" + +#if !defined(GTEST_DEV_EMAIL_) +# define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +# define GTEST_FLAG_PREFIX_ "gtest_" +# define GTEST_FLAG_PREFIX_DASH_ "gtest-" +# define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +# define GTEST_NAME_ "Google Test" +# define GTEST_PROJECT_URL_ "https://github.com/google/googletest/" +#endif // !defined(GTEST_DEV_EMAIL_) + +#if !defined(GTEST_INIT_GOOGLE_TEST_NAME_) +# define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest" +#endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_) // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ @@ -227,82 +292,73 @@ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ -// Determines the platform on which Google Test is compiled. -#ifdef __CYGWIN__ -# define GTEST_OS_CYGWIN 1 -#elif defined __SYMBIAN32__ -# define GTEST_OS_SYMBIAN 1 -#elif defined _WIN32 -# define GTEST_OS_WINDOWS 1 -# ifdef _WIN32_WCE -# define GTEST_OS_WINDOWS_MOBILE 1 -# elif defined(__MINGW__) || defined(__MINGW32__) -# define GTEST_OS_WINDOWS_MINGW 1 -# else -# define GTEST_OS_WINDOWS_DESKTOP 1 -# endif // _WIN32_WCE -#elif defined __APPLE__ -# define GTEST_OS_MAC 1 -# if TARGET_OS_IPHONE -# define GTEST_OS_IOS 1 -# if TARGET_IPHONE_SIMULATOR -# define GTEST_OS_IOS_SIMULATOR 1 -# endif -# endif -#elif defined __linux__ -# define GTEST_OS_LINUX 1 -# if defined __ANDROID__ -# define GTEST_OS_LINUX_ANDROID 1 -# endif -#elif defined __MVS__ -# define GTEST_OS_ZOS 1 -#elif defined(__sun) && defined(__SVR4) -# define GTEST_OS_SOLARIS 1 -#elif defined(_AIX) -# define GTEST_OS_AIX 1 -#elif defined(__hpux) -# define GTEST_OS_HPUX 1 -#elif defined __native_client__ -# define GTEST_OS_NACL 1 -#elif defined __OpenBSD__ -# define GTEST_OS_OPENBSD 1 -#elif defined __QNX__ -# define GTEST_OS_QNX 1 -#endif // __CYGWIN__ - -#ifndef GTEST_LANG_CXX11 -// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when -// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a -// value for __cplusplus, and recent versions of clang, gcc, and -// probably other compilers set that too in C++11 mode. -# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L -// Compiling in at least C++11 mode. -# define GTEST_LANG_CXX11 1 -# else -# define GTEST_LANG_CXX11 0 -# endif +// Macros for disabling Microsoft Visual C++ warnings. +// +// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) +// /* code that triggers warnings C4800 and C4385 */ +// GTEST_DISABLE_MSC_WARNINGS_POP_() +#if defined(_MSC_VER) +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ + __pragma(warning(push)) \ + __pragma(warning(disable: warnings)) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() \ + __pragma(warning(pop)) +#else +// Not all compilers are MSVC +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + +// Clang on Windows does not understand MSVC's pragma warning. +// We need clang-specific way to disable function deprecation warning. +#ifdef __clang__ +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") +#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + _Pragma("clang diagnostic pop") +#else +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() #endif // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. -#if !GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS_MOBILE +# include +# include +# endif +// In order to avoid having to include , use forward declaration +#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) +// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two +// separate (equivalent) structs, instead of using typedef +typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#else +// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. +// This assumption is verified by +// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. +typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#endif +#else // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include -#elif !GTEST_OS_WINDOWS_MOBILE -# include -# include -#endif +#endif // GTEST_OS_WINDOWS #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. # include // NOLINT #endif -// Defines this to true iff Google Test can use POSIX regular expressions. +// Defines this to true if and only if Google Test can use POSIX regular +// expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID // On Android, is only available starting with Gingerbread. @@ -312,7 +368,10 @@ # endif #endif -#if GTEST_HAS_POSIX_RE +#if GTEST_USES_PCRE +// The appropriate headers have already been included. + +#elif GTEST_HAS_POSIX_RE // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already @@ -334,21 +393,34 @@ // simple regex implementation instead. # define GTEST_USES_SIMPLE_RE 1 -#endif // GTEST_HAS_POSIX_RE +#endif // GTEST_USES_PCRE #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. -# if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +# if defined(_MSC_VER) && defined(_CPPUNWIND) +// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__BORLANDC__) +// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS # define _HAS_EXCEPTIONS 1 # endif // _HAS_EXCEPTIONS # define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__clang__) +// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang +// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files, +// there can be cleanups for ObjC exceptions which also need cleanups, even if +// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which +// checks for C++ exceptions starting at clang r206352, but which checked for +// cleanups prior to that. To reliably check for C++ exception availability with +// clang, check for +// __EXCEPTIONS && __has_feature(cxx_exceptions). +# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) # elif defined(__GNUC__) && __EXCEPTIONS -// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +// gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of @@ -356,7 +428,7 @@ // they are enabled unless the user tells us otherwise. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__IBMCPP__) && __EXCEPTIONS -// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +// xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to @@ -375,38 +447,21 @@ # define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. -# error "Google Test cannot be used where ::std::string isn't available." +# error "::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) -#ifndef GTEST_HAS_GLOBAL_STRING -// The user didn't tell us whether ::string is available, so we need -// to figure it out. - -# define GTEST_HAS_GLOBAL_STRING 0 - -#endif // GTEST_HAS_GLOBAL_STRING - #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. -// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring -// is available. - // Cygwin 1.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). -# define GTEST_HAS_STD_WSTRING \ - (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) +#define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + GTEST_OS_HAIKU)) #endif // GTEST_HAS_STD_WSTRING -#ifndef GTEST_HAS_GLOBAL_WSTRING -// The user didn't tell us whether ::wstring is available, so we need -// to figure it out. -# define GTEST_HAS_GLOBAL_WSTRING \ - (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) -#endif // GTEST_HAS_GLOBAL_WSTRING - // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to @@ -414,14 +469,15 @@ # ifdef _MSC_VER -# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +#ifdef _CPPRTTI // MSVC defines this macro if and only if RTTI is enabled. # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif -// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) +// Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is +// enabled. +# elif defined(__GNUC__) # ifdef __GXX_RTTI // When building against STLport with the Android NDK and with @@ -472,13 +528,16 @@ // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD -// The user didn't tell us explicitly, so we assume pthreads support is -// available on Linux and Mac. +// The user didn't tell us explicitly, so we make reasonable assumptions about +// which platforms have pthreads support. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. -# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ - || GTEST_OS_QNX) +#define GTEST_HAS_PTHREAD \ + (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \ + GTEST_OS_HAIKU) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD @@ -490,119 +549,6 @@ # include // NOLINT #endif -// Determines whether Google Test can use tr1/tuple. You can define -// this macro to 0 to prevent Google Test from using tuple (any -// feature depending on tuple with be disabled in this mode). -#ifndef GTEST_HAS_TR1_TUPLE -# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) -// STLport, provided with the Android NDK, has neither or . -# define GTEST_HAS_TR1_TUPLE 0 -# else -// The user didn't tell us not to do it, so we assume it's OK. -# define GTEST_HAS_TR1_TUPLE 1 -# endif -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether Google Test's own tr1 tuple implementation -// should be used. -#ifndef GTEST_USE_OWN_TR1_TUPLE -// The user didn't tell us, so we need to figure it out. - -// We use our own TR1 tuple if we aren't sure the user has an -// implementation of it already. At this time, libstdc++ 4.0.0+ and -// MSVC 2010 are the only mainstream standard libraries that come -// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler -// pretends to be GCC by defining __GNUC__ and friends, but cannot -// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 -// tuple in a 323 MB Feature Pack download, which we cannot assume the -// user has. QNX's QCC compiler is a modified GCC but it doesn't -// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, -// and it can be used with some compilers that define __GNUC__. -# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ - && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 -# define GTEST_ENV_HAS_TR1_TUPLE_ 1 -# endif - -// C++11 specifies that provides std::tuple. Use that if gtest is used -// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 -// can build with clang but need to use gcc4.2's libstdc++). -# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) -# define GTEST_ENV_HAS_STD_TUPLE_ 1 -# endif - -# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ -# define GTEST_USE_OWN_TR1_TUPLE 0 -# else -# define GTEST_USE_OWN_TR1_TUPLE 1 -# endif - -#endif // GTEST_USE_OWN_TR1_TUPLE - -// To avoid conditional compilation everywhere, we make it -// gtest-port.h's responsibility to #include the header implementing -// tr1/tuple. -#if GTEST_HAS_TR1_TUPLE - -# if GTEST_USE_OWN_TR1_TUPLE -# include "gtest/internal/gtest-tuple.h" -# elif GTEST_ENV_HAS_STD_TUPLE_ -# include -// C++11 puts its tuple into the ::std namespace rather than -// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. -// This causes undefined behavior, but supported compilers react in -// the way we intend. -namespace std { -namespace tr1 { -using ::std::get; -using ::std::make_tuple; -using ::std::tuple; -using ::std::tuple_element; -using ::std::tuple_size; -} -} - -# elif GTEST_OS_SYMBIAN - -// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to -// use STLport's tuple implementation, which unfortunately doesn't -// work as the copy of STLport distributed with Symbian is incomplete. -// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to -// use its own tuple implementation. -# ifdef BOOST_HAS_TR1_TUPLE -# undef BOOST_HAS_TR1_TUPLE -# endif // BOOST_HAS_TR1_TUPLE - -// This prevents , which defines -// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . -# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED -# include - -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) -// GCC 4.0+ implements tr1/tuple in the header. This does -// not conform to the TR1 spec, which requires the header to be . - -# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -// Until version 4.3.2, gcc has a bug that causes , -// which is #included by , to not compile when RTTI is -// disabled. _TR1_FUNCTIONAL is the header guard for -// . Hence the following #define is a hack to prevent -// from being included. -# define _TR1_FUNCTIONAL 1 -# include -# undef _TR1_FUNCTIONAL // Allows the user to #include - // if he chooses to. -# else -# include // NOLINT -# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 - -# else -// If the compiler is not GCC 4.0+, we assume the user is using a -// spec-conforming TR1 implementation. -# include // NOLINT -# endif // GTEST_USE_OWN_TR1_TUPLE - -#endif // GTEST_HAS_TR1_TUPLE - // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. @@ -612,8 +558,12 @@ using ::std::tuple_size; # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID -// On Android, clone() is only available on ARM starting with Gingerbread. -# if defined(__arm__) && __ANDROID_API__ >= 9 +// On Android, clone() became available at different API levels for each 32-bit +// architecture. +# if defined(__LP64__) || \ + (defined(__arm__) && __ANDROID_API__ >= 9) || \ + (defined(__mips__) && __ANDROID_API__ >= 12) || \ + (defined(__i386__) && __ANDROID_API__ >= 17) # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 @@ -632,55 +582,41 @@ using ::std::tuple_size; #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 -# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +# endif // !GTEST_OS_WINDOWS_MOBILE #endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. -// Google Test does not support death tests for VC 7.1 and earlier as -// abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ - GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD || GTEST_OS_QNX) +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \ + GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU) # define GTEST_HAS_DEATH_TEST 1 -# include // NOLINT #endif -// We don't support MSVC 7.1 with exceptions disabled now. Therefore -// all the compilers we care about are adequate for supporting -// value-parameterized tests. -#define GTEST_HAS_PARAM_TEST 1 - // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. -#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ +#if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) # define GTEST_HAS_TYPED_TEST 1 # define GTEST_HAS_TYPED_TEST_P 1 #endif -// Determines whether to support Combine(). This only makes sense when -// value-parameterized tests are enabled. The implementation doesn't -// work on Sun Studio since it doesn't understand templated conversion -// operators. -#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) -# define GTEST_HAS_COMBINE 1 -#endif - // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ - (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_AIX || GTEST_OS_OS2) // Determines whether test results can be streamed to a socket. -#if GTEST_OS_LINUX +#if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD # define GTEST_CAN_STREAM_RESULTS_ 1 #endif @@ -713,19 +649,42 @@ using ::std::tuple_size; // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) -#else +#elif defined(__clang__) +# if __has_attribute(unused) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +# endif +#endif +#ifndef GTEST_ATTRIBUTE_UNUSED_ # define GTEST_ATTRIBUTE_UNUSED_ #endif +// Use this annotation before a function that takes a printf format string. +#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) +# if defined(__MINGW_PRINTF_FORMAT) +// MinGW has two different printf implementations. Ensure the format macro +// matches the selected implementation. See +// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \ + first_to_check))) +# else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +# endif +#else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) +#endif + + // A macro to disallow operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_ASSIGN_(type)\ - void operator=(type const &) +#define GTEST_DISALLOW_ASSIGN_(type) \ + void operator=(type const &) = delete // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ - type(type const &);\ +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ + type(type const &) = delete; \ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared @@ -733,11 +692,24 @@ using ::std::tuple_size; // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; -#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +#if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else # define GTEST_MUST_USE_RESULT_ -#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC +#endif // __GNUC__ && !COMPILER_ICC + +// MS C++ compiler emits warning when a conditional expression is compile time +// constant. In some contexts this warning is false positive and needs to be +// suppressed. Use the following two macros in such cases: +// +// GTEST_INTENTIONAL_CONST_COND_PUSH_() +// while (true) { +// GTEST_INTENTIONAL_CONST_COND_POP_() +// } +# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) +# define GTEST_INTENTIONAL_CONST_COND_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally @@ -755,19 +727,39 @@ using ::std::tuple_size; #endif // GTEST_HAS_SEH -#ifdef _MSC_VER +#ifndef GTEST_IS_THREADSAFE + +#define GTEST_IS_THREADSAFE \ + (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \ + (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \ + GTEST_HAS_PTHREAD) +#endif // GTEST_IS_THREADSAFE + +// GTEST_API_ qualifies all symbols that must be exported. The definitions below +// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in +// gtest/internal/custom/gtest-port.h +#ifndef GTEST_API_ + +#ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) # elif GTEST_CREATE_SHARED_LIBRARY # define GTEST_API_ __declspec(dllexport) # endif - +#elif __GNUC__ >= 4 || defined(__clang__) +# define GTEST_API_ __attribute__((visibility ("default"))) #endif // _MSC_VER +#endif // GTEST_API_ + #ifndef GTEST_API_ # define GTEST_API_ -#endif +#endif // GTEST_API_ + +#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE +# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" +#endif // GTEST_DEFAULT_DEATH_TEST_STYLE #ifdef __GNUC__ // Ask the compiler to never inline a given function. @@ -777,16 +769,75 @@ using ::std::tuple_size; #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) -# define GTEST_HAS_CXXABI_H_ 1 -#else -# define GTEST_HAS_CXXABI_H_ 0 +#if !defined(GTEST_HAS_CXXABI_H_) +# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) +# define GTEST_HAS_CXXABI_H_ 1 +# else +# define GTEST_HAS_CXXABI_H_ 0 +# endif #endif +// A function level attribute to disable checking for use of uninitialized +// memory when built with MemorySanitizer. +#if defined(__clang__) +# if __has_feature(memory_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \ + __attribute__((no_sanitize_memory)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +# endif // __has_feature(memory_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +#endif // __clang__ + +// A function level attribute to disable AddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(address_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ + __attribute__((no_sanitize_address)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +# endif // __has_feature(address_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +#endif // __clang__ + +// A function level attribute to disable HWAddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(hwaddress_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \ + __attribute__((no_sanitize("hwaddress"))) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +# endif // __has_feature(hwaddress_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +#endif // __clang__ + +// A function level attribute to disable ThreadSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(thread_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ + __attribute__((no_sanitize_thread)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +# endif // __has_feature(thread_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +#endif // __clang__ + namespace testing { class Message; +// Legacy imports for backwards compatibility. +// New code should use std:: names directly. +using std::get; +using std::make_tuple; +using std::tuple; +using std::tuple_element; +using std::tuple_size; + namespace internal { // A secret type that Google Test users don't know about. It has no @@ -794,134 +845,30 @@ namespace internal { // Secret object, which is what we want. class Secret; -// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: -// -// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, -// content_type_names_incorrect_size); -// -// or to make sure a struct is smaller than a certain size: -// -// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -template -struct CompileAssert { -}; - -#define GTEST_COMPILE_ASSERT_(expr, msg) \ - typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ - msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ - -// Implementation details of GTEST_COMPILE_ASSERT_: -// -// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 -// elements (and thus is invalid) when the expression is false. -// -// - The simpler definition -// -// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] -// -// does not work, as gcc supports variable-length arrays whose sizes -// are determined at run-time (this is gcc's extension and not part -// of the C++ standard). As a result, gcc fails to reject the -// following code with the simple definition: -// -// int foo; -// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. +// The GTEST_COMPILE_ASSERT_ is a legacy macro used to verify that a compile +// time expression is true (in new code, use static_assert instead). For +// example, you could use it to verify the size of a static array: // -// - By using the type CompileAssert<(bool(expr))>, we ensures that -// expr is a compile-time constant. (Template arguments must be -// determined at compile-time.) +// GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, +// names_incorrect_size); // -// - The outter parentheses in CompileAssert<(bool(expr))> are necessary -// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written -// -// CompileAssert -// -// instead, these compilers will refuse to compile -// -// GTEST_COMPILE_ASSERT_(5 > 0, some_message); -// -// (They seem to think the ">" in "5 > 0" marks the end of the -// template argument list.) -// -// - The array size is (bool(expr) ? 1 : -1), instead of simply -// -// ((expr) ? 1 : -1). -// -// This is to avoid running into a bug in MS VC 7.1, which -// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. +// The second argument to the macro must be a valid C++ identifier. If the +// expression is false, compiler will issue an error containing this identifier. +#define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) -// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. -// -// This template is declared, but intentionally undefined. -template -struct StaticAssertTypeEqHelper; - -template -struct StaticAssertTypeEqHelper {}; - -#if GTEST_HAS_GLOBAL_STRING -typedef ::string string; -#else -typedef ::std::string string; -#endif // GTEST_HAS_GLOBAL_STRING - -#if GTEST_HAS_GLOBAL_WSTRING -typedef ::wstring wstring; -#elif GTEST_HAS_STD_WSTRING -typedef ::std::wstring wstring; -#endif // GTEST_HAS_GLOBAL_WSTRING +// Evaluates to the number of elements in 'array'. +#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); -// Defines scoped_ptr. - -// This implementation of scoped_ptr is PARTIAL - it only contains -// enough stuff to satisfy Google Test's need. -template -class scoped_ptr { - public: - typedef T element_type; - - explicit scoped_ptr(T* p = NULL) : ptr_(p) {} - ~scoped_ptr() { reset(); } - - T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_; } - T* get() const { return ptr_; } - - T* release() { - T* const ptr = ptr_; - ptr_ = NULL; - return ptr; - } - - void reset(T* p = NULL) { - if (p != ptr_) { - if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. - delete ptr_; - } - ptr_ = p; - } - } - - private: - T* ptr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); -}; - // Defines RE. +#if GTEST_USES_PCRE +// if used, PCRE is injected by custom/gtest-port.h +#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE + // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { @@ -933,25 +880,16 @@ class GTEST_API_ RE { // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT -#if GTEST_HAS_GLOBAL_STRING - - RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT - -#endif // GTEST_HAS_GLOBAL_STRING - RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } - // FullMatch(str, re) returns true iff regular expression re matches - // the entire str. - // PartialMatch(str, re) returns true iff regular expression re + // FullMatch(str, re) returns true if and only if regular expression re + // matches the entire str. + // PartialMatch(str, re) returns true if and only if regular expression re // matches a substring of str (including str itself). - // - // TODO(wan@google.com): make FullMatch() and PartialMatch() work - // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } @@ -959,43 +897,30 @@ class GTEST_API_ RE { return PartialMatch(str.c_str(), re); } -#if GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const ::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } - -#endif // GTEST_HAS_GLOBAL_STRING - static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); - - // We use a const char* instead of an std::string, as Google Test used to be - // used where std::string is not available. TODO(wan@google.com): change to - // std::string. const char* pattern_; bool is_valid_; -#if GTEST_USES_POSIX_RE +# if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). -#else // GTEST_USES_SIMPLE_RE +# else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); -#endif +# endif GTEST_DISALLOW_ASSIGN_(RE); }; +#endif // GTEST_USES_PCRE + // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); @@ -1037,13 +962,18 @@ class GTEST_API_ GTestLog { GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; -#define GTEST_LOG_(severity) \ +#if !defined(GTEST_LOG_) + +# define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} -inline void FlushInfoLog() { fflush(NULL); } +inline void FlushInfoLog() { fflush(nullptr); } +#endif // !defined(GTEST_LOG_) + +#if !defined(GTEST_CHECK_) // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition @@ -1058,12 +988,13 @@ inline void FlushInfoLog() { fflush(NULL); } // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. -#define GTEST_CHECK_(condition) \ +# define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " +#endif // !defined(GTEST_CHECK_) // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this @@ -1075,6 +1006,26 @@ inline void FlushInfoLog() { fflush(NULL); } GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error +// Transforms "T" into "const T&" according to standard reference collapsing +// rules (this is only needed as a backport for C++98 compilers that do not +// support reference collapsing). Specifically, it transforms: +// +// char ==> const char& +// const char ==> const char& +// char& ==> char& +// const char& ==> const char& +// +// Note that the non-const reference will not have "const" added. This is +// standard, and necessary so that "T" can always bind to "const T&". +template +struct ConstRef { typedef const T& type; }; +template +struct ConstRef { typedef T& type; }; + +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + typename ::testing::internal::ConstRef::type + // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in @@ -1125,14 +1076,16 @@ inline To DownCast_(From* f) { // so we only accept pointers // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. + GTEST_INTENTIONAL_CONST_COND_PUSH_() if (false) { - const To to = NULL; - ::testing::internal::ImplicitCast_(to); + GTEST_INTENTIONAL_CONST_COND_POP_() + const To to = nullptr; + ::testing::internal::ImplicitCast_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! - GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); + GTEST_CHECK_(f == nullptr || dynamic_cast(f) != nullptr); #endif return static_cast(f); } @@ -1146,6 +1099,11 @@ template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); +#endif + +#if GTEST_HAS_DOWNCAST_ + return ::down_cast(base); +#elif GTEST_HAS_RTTI return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. @@ -1166,34 +1124,45 @@ GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION +// Returns the size (in bytes) of a file. +GTEST_API_ size_t GetFileSize(FILE* file); +// Reads the entire content of a file as a string. +GTEST_API_ std::string ReadEntireFile(FILE* file); -#if GTEST_HAS_DEATH_TEST +// All command line arguments. +GTEST_API_ std::vector GetArgvs(); -const ::std::vector& GetInjectableArgvs(); -void SetInjectableArgvs(const ::std::vector* - new_argvs); +#if GTEST_HAS_DEATH_TEST -// A copy of all command line arguments. Set by InitGoogleTest(). -extern ::std::vector g_argvs; +std::vector GetInjectableArgvs(); +// Deprecated: pass the args vector by value instead. +void SetInjectableArgvs(const std::vector* new_argvs); +void SetInjectableArgvs(const std::vector& new_argvs); +void ClearInjectableArgvs(); #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. - -#if GTEST_HAS_PTHREAD - -// Sleeps for (roughly) n milli-seconds. This function is only for -// testing Google Test's own constructs. Don't use it in user tests, -// either directly or indirectly. +#if GTEST_IS_THREADSAFE +# if GTEST_HAS_PTHREAD +// Sleeps for (roughly) n milliseconds. This function is only for testing +// Google Test's own constructs. Don't use it in user tests, either +// directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; - nanosleep(&time, NULL); + nanosleep(&time, nullptr); } +# endif // GTEST_HAS_PTHREAD +# if GTEST_HAS_NOTIFICATION_ +// Notification has already been imported into the namespace. +// Nothing to do here. + +# elif GTEST_HAS_PTHREAD // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. @@ -1203,7 +1172,7 @@ inline void SleepMilliseconds(int n) { class Notification { public: Notification() : notified_(false) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); } ~Notification() { pthread_mutex_destroy(&mutex_); @@ -1237,6 +1206,63 @@ class Notification { GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +GTEST_API_ void SleepMilliseconds(int n); + +// Provides leak-safe Windows kernel handle ownership. +// Used in death tests and in threading support. +class GTEST_API_ AutoHandle { + public: + // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to + // avoid including in this header file. Including is + // undesirable because it defines a lot of symbols and macros that tend to + // conflict with client code. This assumption is verified by + // WindowsTypesTest.HANDLEIsVoidStar. + typedef void* Handle; + AutoHandle(); + explicit AutoHandle(Handle handle); + + ~AutoHandle(); + + Handle Get() const; + void Reset(); + void Reset(Handle handle); + + private: + // Returns true if and only if the handle is a valid handle object that can be + // closed. + bool IsCloseable() const; + + Handle handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class GTEST_API_ Notification { + public: + Notification(); + void Notify(); + void WaitForNotification(); + + private: + AutoHandle event_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; +# endif // GTEST_HAS_NOTIFICATION_ + +// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD +// defined, but we don't want to use MinGW's pthreads implementation, which +// has conformance problems with some versions of the POSIX standard. +# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW + // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a @@ -1256,7 +1282,7 @@ class ThreadWithParamBase { // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast(thread)->Run(); - return NULL; + return nullptr; } // Helper class for testing Google Test's multi-threading constructs. @@ -1274,10 +1300,9 @@ extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { template class ThreadWithParam : public ThreadWithParamBase { public: - typedef void (*UserThreadFunc)(T); + typedef void UserThreadFunc(T); - ThreadWithParam( - UserThreadFunc func, T param, Notification* thread_can_start) + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), @@ -1286,54 +1311,321 @@ class ThreadWithParam : public ThreadWithParamBase { // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( - pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + pthread_create(&thread_, nullptr, &ThreadFuncWithCLinkage, base)); } - ~ThreadWithParam() { Join(); } + ~ThreadWithParam() override { Join(); } void Join() { if (!finished_) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr)); finished_ = true; } } - virtual void Run() { - if (thread_can_start_ != NULL) - thread_can_start_->WaitForNotification(); + void Run() override { + if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification(); func_(param_); } private: - const UserThreadFunc func_; // User-supplied thread function. + UserThreadFunc* const func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; - bool finished_; // true iff we know that the thread function has finished. + bool finished_; // true if and only if we know that the thread function has + // finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; +# endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD || + // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ + +# if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ +// Mutex and ThreadLocal have already been imported into the namespace. +// Nothing to do here. -// MutexBase and Mutex implement mutex on pthreads-based platforms. They -// are used in conjunction with class MutexLock: +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +// Mutex implements mutex on Windows platforms. It is used in conjunction +// with class MutexLock: // // Mutex mutex; // ... -// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end -// // of the current scope. -// -// MutexBase implements behavior for both statically and dynamically -// allocated mutexes. Do not use MutexBase directly. Instead, write -// the following to define a static mutex: +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the +// // end of the current scope. // +// A static Mutex *must* be defined or declared using one of the following +// macros: // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// (A non-static Mutex is defined/declared in the usual way). +class GTEST_API_ Mutex { + public: + enum MutexType { kStatic = 0, kDynamic = 1 }; + // We rely on kStaticMutex being 0 as it is to what the linker initializes + // type_ in static mutexes. critical_section_ will be initialized lazily + // in ThreadSafeLazyInit(). + enum StaticConstructorSelector { kStaticMutex = 0 }; + + // This constructor intentionally does nothing. It relies on type_ being + // statically initialized to 0 (effectively setting it to kStatic) and on + // ThreadSafeLazyInit() to lazily initialize the rest of the members. + explicit Mutex(StaticConstructorSelector /*dummy*/) {} + + Mutex(); + ~Mutex(); + + void Lock(); + + void Unlock(); + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld(); + + private: + // Initializes owner_thread_id_ and critical_section_ in static mutexes. + void ThreadSafeLazyInit(); + + // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503, + // we assume that 0 is an invalid value for thread IDs. + unsigned int owner_thread_id_; + + // For static mutexes, we rely on these members being initialized to zeros + // by the linker. + MutexType type_; + long critical_section_init_phase_; // NOLINT + GTEST_CRITICAL_SECTION* critical_section_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + Mutex* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Base class for ValueHolder. Allows a caller to hold and delete a value +// without knowing its type. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Provides a way for a thread to send notifications to a ThreadLocal +// regardless of its parameter type. +class ThreadLocalBase { + public: + // Creates a new ValueHolder object holding a default value passed to + // this ThreadLocal's constructor and returns it. It is the caller's + // responsibility not to call this when the ThreadLocal instance already + // has a value on the current thread. + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; + + protected: + ThreadLocalBase() {} + virtual ~ThreadLocalBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase); +}; + +// Maps a thread to a set of ThreadLocals that have values instantiated on that +// thread and notifies them when the thread exits. A ThreadLocal instance is +// expected to persist until all threads it has values on have terminated. +class GTEST_API_ ThreadLocalRegistry { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance); + + // Invoked when a ThreadLocal instance is destroyed. + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance); +}; + +class GTEST_API_ ThreadWithParamBase { + public: + void Join(); + + protected: + class Runnable { + public: + virtual ~Runnable() {} + virtual void Run() = 0; + }; + + ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); + virtual ~ThreadWithParamBase(); + + private: + AutoHandle thread_; +}; + +// Helper class for testing Google Test's multi-threading constructs. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void UserThreadFunc(T); + + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) + : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { + } + virtual ~ThreadWithParam() {} + + private: + class RunnableImpl : public Runnable { + public: + RunnableImpl(UserThreadFunc* func, T param) + : func_(func), + param_(param) { + } + virtual ~RunnableImpl() {} + virtual void Run() { + func_(param_); + } + + private: + UserThreadFunc* const func_; + const T param_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); + }; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// Implements thread-local storage on Windows systems. // -// You can forward declare a static mutex like this: +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. // -// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); // -// To create a dynamic mutex, just define an object of type Mutex. +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// The users of a TheadLocal instance have to make sure that all but one +// threads (including the main one) using that instance have exited before +// destroying it. Otherwise, the per-thread objects managed for them by the +// ThreadLocal instance are not guaranteed to be destroyed on all platforms. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal : public ThreadLocalBase { + public: + ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : default_factory_(new InstanceValueHolderFactory(value)) {} + + ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of T. Can be deleted via its base class without the caller + // knowing the type of T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + ValueHolder() : value_() {} + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + + T* GetOrCreateValue() const { + return static_cast( + ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); + } + + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { + return default_factory_->MakeNewHolder(); + } + + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + virtual ValueHolder* MakeNewHolder() const { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + + std::unique_ptr default_factory_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# elif GTEST_HAS_PTHREAD + +// MutexBase and Mutex implement mutex on pthreads-based platforms. class MutexBase { public: // Acquires this mutex. @@ -1378,8 +1670,8 @@ class MutexBase { }; // Forward-declares a static mutex. -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::MutexBase mutex +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, @@ -1387,15 +1679,15 @@ class MutexBase { // particular, the owner_ field (a pthread_t) is not explicitly initialized. // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0} // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); has_owner_ = false; } ~Mutex() { @@ -1406,9 +1698,11 @@ class Mutex : public MutexBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; -// We cannot name this class MutexLock as the ctor declaration would +// We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some -// platforms. Hence the typedef trick below. +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) @@ -1442,41 +1736,14 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) { } // Implements thread-local storage on pthreads-based systems. -// -// // Thread 1 -// ThreadLocal tl(100); // 100 is the default value for each thread. -// -// // Thread 2 -// tl.set(150); // Changes the value for thread 2 only. -// EXPECT_EQ(150, tl.get()); -// -// // Thread 1 -// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. -// tl.set(200); -// EXPECT_EQ(200, tl.get()); -// -// The template type argument T must have a public copy constructor. -// In addition, the default ThreadLocal constructor requires T to have -// a public default constructor. -// -// An object managed for a thread by a ThreadLocal instance is deleted -// when the thread exits. Or, if the ThreadLocal instance dies in -// that thread, when the ThreadLocal dies. It's the user's -// responsibility to ensure that all other threads using a ThreadLocal -// have exited when it dies, or the per-thread objects for those -// threads will not be deleted. -// -// Google Test only uses global ThreadLocal objects. That means they -// will die after main() has returned. Therefore, no per-thread -// object managed by Google Test will be leaked as long as all threads -// using Google Test have exited when main() returns. template -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: - ThreadLocal() : key_(CreateKey()), - default_() {} - explicit ThreadLocal(const T& value) : key_(CreateKey()), - default_(value) {} + ThreadLocal() + : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : key_(CreateKey()), + default_factory_(new InstanceValueHolderFactory(value)) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. @@ -1496,6 +1763,7 @@ class ThreadLocal { // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: + ValueHolder() : value_() {} explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } @@ -1517,26 +1785,58 @@ class ThreadLocal { T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast(pthread_getspecific(key_)); - if (holder != NULL) { + if (holder != nullptr) { return CheckedDowncastToActualType(holder)->pointer(); } - ValueHolder* const new_holder = new ValueHolder(default_); + ValueHolder* const new_holder = default_factory_->MakeNewHolder(); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + virtual ValueHolder* MakeNewHolder() const { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; - const T default_; // The default value for each thread. + std::unique_ptr default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; -# define GTEST_IS_THREADSAFE 1 +# endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ -#else // GTEST_HAS_PTHREAD +#else // GTEST_IS_THREADSAFE // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where @@ -1556,6 +1856,11 @@ class Mutex { # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT @@ -1564,7 +1869,7 @@ class GTestMutexLock { typedef GTestMutexLock MutexLock; template -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} @@ -1576,68 +1881,14 @@ class ThreadLocal { T value_; }; -// The above synchronization primitives have dummy implementations. -// Therefore Google Test is not thread-safe. -# define GTEST_IS_THREADSAFE 0 - -#endif // GTEST_HAS_PTHREAD +#endif // GTEST_IS_THREADSAFE // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. GTEST_API_ size_t GetThreadCount(); -// Passing non-POD classes through ellipsis (...) crashes the ARM -// compiler and generates a warning in Sun Studio. The Nokia Symbian -// and the IBM XL C/C++ compiler try to instantiate a copy constructor -// for objects passed through ellipsis (...), failing for uncopyable -// objects. We define this to ensure that only POD is passed through -// ellipsis on these systems. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_ELLIPSIS_NEEDS_POD_ 1 -#else -# define GTEST_CAN_COMPARE_NULL 1 -#endif - -// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between -// const T& and const T* in a function template. These compilers -// _can_ decide between class template specializations for T and T*, -// so a tr1::type_traits-like is_pointer works. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) -# define GTEST_NEEDS_IS_POINTER_ 1 -#endif - -template -struct bool_constant { - typedef bool_constant type; - static const bool value = bool_value; -}; -template const bool bool_constant::value; - -typedef bool_constant false_type; -typedef bool_constant true_type; - -template -struct is_pointer : public false_type {}; - -template -struct is_pointer : public true_type {}; - -template -struct IteratorTraits { - typedef typename Iterator::value_type value_type; -}; - -template -struct IteratorTraits { - typedef T value_type; -}; - -template -struct IteratorTraits { - typedef T value_type; -}; +template +using bool_constant = std::integral_constant; #if GTEST_OS_WINDOWS # define GTEST_PATH_SEP_ "\\" @@ -1690,6 +1941,13 @@ inline char ToUpper(char ch) { return static_cast(toupper(static_cast(ch))); } +inline std::string StripTrailingSpaces(std::string str) { + std::string::iterator it = str.end(); + while (it != str.begin() && IsSpace(*--it)) + it = str.erase(it); + return str; +} + // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these @@ -1753,11 +2011,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } // Functions deprecated by MSVC 8.0. -#ifdef _MSC_VER -// Temporarily disable warning 4996 (deprecated function). -# pragma warning(push) -# pragma warning(disable:4996) -#endif +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); @@ -1767,7 +2021,7 @@ inline const char* StrNCpy(char* dest, const char* src, size_t n) { // StrError() aren't needed on Windows CE at this time and thus not // defined there. -#if !GTEST_OS_WINDOWS_MOBILE +#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { @@ -1791,30 +2045,29 @@ inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT // We are on Windows CE, which has no environment variables. - return NULL; + static_cast(name); // To prevent 'unused argument' warning. + return nullptr; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); - return (env != NULL && env[0] != '\0') ? env : NULL; + return (env != nullptr && env[0] != '\0') ? env : nullptr; #else return getenv(name); #endif } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif +GTEST_DISABLE_MSC_DEPRECATED_POP_() #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. -void Abort(); +[[noreturn]] void Abort(); #else -inline void Abort() { abort(); } +[[noreturn]] inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix @@ -1824,13 +2077,12 @@ inline void Abort() { abort(); } // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. -#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +#if _MSC_VER && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. # define GTEST_SNPRINTF_(buffer, size, format, ...) \ _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) -// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't -// complain about _snprintf. +// Windows CE does not define _snprintf_s # define GTEST_SNPRINTF_ _snprintf #else # define GTEST_SNPRINTF_ snprintf @@ -1907,42 +2159,73 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. -#define GTEST_FLAG(name) FLAGS_gtest_##name +#if !defined(GTEST_FLAG) +# define GTEST_FLAG(name) FLAGS_gtest_##name +#endif // !defined(GTEST_FLAG) + +#if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) +# define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 +#endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) + +#if !defined(GTEST_DECLARE_bool_) +# define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver // Macros for declaring flags. -#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) -#define GTEST_DECLARE_int32_(name) \ +# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +# define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) -#define GTEST_DECLARE_string_(name) \ +# define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. -#define GTEST_DEFINE_bool_(name, default_val, doc) \ +# define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_int32_(name, default_val, doc) \ +# define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_string_(name, default_val, doc) \ +# define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) +#endif // !defined(GTEST_DECLARE_bool_) + // Thread annotations -#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) -#define GTEST_LOCK_EXCLUDED_(locks) +#if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) +# define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) +# define GTEST_LOCK_EXCLUDED_(locks) +#endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. -// TODO(chandlerc): Find a better way to refactor flag and environment parsing -// out of both gtest-port.cc and gtest.cc to avoid exporting this utility -// function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +std::string OutputFlagAlsoCheckEnvVar(); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing +#if !defined(GTEST_INTERNAL_DEPRECATED) + +// Internal Macro to mark an API deprecated, for googletest usage only +// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or +// GTEST_INTERNAL_DEPRECATED(message) myFunction(); Every usage of +// a deprecated entity will trigger a warning when compiled with +// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler). +// For msvc /W3 option will need to be used +// Note that for 'other' compilers this macro evaluates to nothing to prevent +// compilations errors. +#if defined(_MSC_VER) +#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__GNUC__) +#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message))) +#else +#define GTEST_INTERNAL_DEPRECATED(message) +#endif + +#endif // !defined(GTEST_INTERNAL_DEPRECATED) + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/test/gtest/include/gtest/internal/gtest-string.h b/test/gtest/include/gtest/internal/gtest-string.h index 97f1a7fdd2..82aaa63bf4 100644 --- a/test/gtest/include/gtest/internal/gtest-string.h +++ b/test/gtest/include/gtest/internal/gtest-string.h @@ -27,17 +27,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // -// This header file is #included by . +// This header file is #included by gtest-internal.h. // It should not be #included by other files. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ @@ -94,7 +94,8 @@ class GTEST_API_ String { static const char* Utf16ToAnsi(LPCWSTR utf16_str); #endif - // Compares two C strings. Returns true iff they have the same content. + // Compares two C strings. Returns true if and only if they have the same + // content. // // Unlike strcmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, @@ -107,16 +108,16 @@ class GTEST_API_ String { // returned. static std::string ShowWideCString(const wchar_t* wide_c_str); - // Compares two wide C strings. Returns true iff they have the same - // content. + // Compares two wide C strings. Returns true if and only if they have the + // same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); - // Compares two C strings, ignoring case. Returns true iff they - // have the same content. + // Compares two C strings, ignoring case. Returns true if and only if + // they have the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL C string, @@ -124,8 +125,8 @@ class GTEST_API_ String { static bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs); - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. + // Compares two wide C strings, ignoring case. Returns true if and only if + // they have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, @@ -139,8 +140,8 @@ class GTEST_API_ String { static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); - // Returns true iff the given string ends with the given suffix, ignoring - // case. Any string is considered to end with an empty suffix. + // Returns true if and only if the given string ends with the given suffix, + // ignoring case. Any string is considered to end with an empty suffix. static bool EndsWithCaseInsensitive( const std::string& str, const std::string& suffix); @@ -150,6 +151,9 @@ class GTEST_API_ String { // Formats an int value as "%X". static std::string FormatHexInt(int value); + // Formats an int value as "%X". + static std::string FormatHexUInt32(UInt32 value); + // Formats a byte as "%02X". static std::string FormatByte(unsigned char value); diff --git a/test/gtest/include/gtest/internal/gtest-tuple.h b/test/gtest/include/gtest/internal/gtest-tuple.h index 7b3dfc312d..e9b405340a 100644 --- a/test/gtest/include/gtest/internal/gtest-tuple.h +++ b/test/gtest/include/gtest/internal/gtest-tuple.h @@ -53,6 +53,14 @@ private: #endif +// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict +// with our own definitions. Therefore using our own tuple does not work on +// those compilers. +#if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */ +# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ +GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." +#endif + // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple= 1600 /* 1600 is Visual Studio 2010 */ +# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ +GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." +#endif + $range i 0..n-1 $range j 0..n diff --git a/test/gtest/include/gtest/internal/gtest-type-util.h b/test/gtest/include/gtest/internal/gtest-type-util.h index e46f7cfcb4..3d7542d1fb 100644 --- a/test/gtest/include/gtest/internal/gtest-type-util.h +++ b/test/gtest/include/gtest/internal/gtest-type-util.h @@ -30,17 +30,17 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most 50 types in a list, and at most 50 -// type-parameterized tests in one type-parameterized test case. +// type-parameterized tests in one type-parameterized test suite. // Please contact googletestframework@googlegroups.com if you need // more. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ @@ -57,6 +57,22 @@ namespace testing { namespace internal { +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. @@ -72,10 +88,10 @@ std::string GetTypeName() { # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ - char* const readable_name = __cxa_demangle(name, 0, 0, &status); + char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); - return name_str; + return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC @@ -89,18 +105,6 @@ std::string GetTypeName() { #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P -// AssertyTypeEq::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template -struct AssertTypeEq; - -template -struct AssertTypeEq { - typedef bool type; -}; - // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't @@ -3295,8 +3299,8 @@ struct Templates list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). +// or a Types<...> list in TYPED_TEST_SUITE() and +// INSTANTIATE_TYPED_TEST_SUITE_P(). template struct TypeList { diff --git a/test/gtest/include/gtest/internal/gtest-type-util.h.pump b/test/gtest/include/gtest/internal/gtest-type-util.h.pump index 251fdf025b..5e31b7b320 100644 --- a/test/gtest/include/gtest/internal/gtest-type-util.h.pump +++ b/test/gtest/include/gtest/internal/gtest-type-util.h.pump @@ -28,17 +28,18 @@ $var n = 50 $$ Maximum length of type lists we want to support. // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most $n types in a list, and at most $n -// type-parameterized tests in one type-parameterized test case. +// type-parameterized tests in one type-parameterized test suite. // Please contact googletestframework@googlegroups.com if you need // more. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ @@ -55,6 +56,22 @@ $var n = 50 $$ Maximum length of type lists we want to support. namespace testing { namespace internal { +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. @@ -70,10 +87,10 @@ std::string GetTypeName() { # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ - char* const readable_name = __cxa_demangle(name, 0, 0, &status); + char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); - return name_str; + return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC @@ -87,18 +104,6 @@ std::string GetTypeName() { #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P -// AssertyTypeEq::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template -struct AssertTypeEq; - -template -struct AssertTypeEq { - typedef bool type; -}; - // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't @@ -274,8 +279,8 @@ struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> { ]] // The TypeList template makes it possible to use either a single type -// or a Types<...> list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). +// or a Types<...> list in TYPED_TEST_SUITE() and +// INSTANTIATE_TYPED_TEST_SUITE_P(). template struct TypeList { diff --git a/test/gtest/src/gtest-all.cc b/test/gtest/src/gtest-all.cc index 0a9cee5223..ad292905cf 100644 --- a/test/gtest/src/gtest-all.cc +++ b/test/gtest/src/gtest-all.cc @@ -26,10 +26,9 @@ // 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. + // -// Author: mheule@google.com (Markus Heule) -// -// Google C++ Testing Framework (Google Test) +// Google C++ Testing and Mocking Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. @@ -42,6 +41,7 @@ #include "src/gtest.cc" #include "src/gtest-death-test.cc" #include "src/gtest-filepath.cc" +#include "src/gtest-matchers.cc" #include "src/gtest-port.cc" #include "src/gtest-printers.cc" #include "src/gtest-test-part.cc" diff --git a/test/gtest/src/gtest-death-test.cc b/test/gtest/src/gtest-death-test.cc index a6023fce4f..da09a1cfc2 100644 --- a/test/gtest/src/gtest-death-test.cc +++ b/test/gtest/src/gtest-death-test.cc @@ -26,13 +26,16 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) + // // This file implements death tests. #include "gtest/gtest-death-test.h" + +#include + #include "gtest/internal/gtest-port.h" +#include "gtest/internal/custom/gtest.h" #if GTEST_HAS_DEATH_TEST @@ -61,26 +64,36 @@ # include # endif // GTEST_OS_QNX +# if GTEST_OS_FUCHSIA +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# endif // GTEST_OS_FUCHSIA + #endif // GTEST_HAS_DEATH_TEST #include "gtest/gtest-message.h" #include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. -static const char kDefaultDeathTestStyle[] = "fast"; +// +// This is defined in internal/gtest-port.h as "fast", but can be overridden by +// a definition in internal/custom/gtest-port.h. The recommended value, which is +// used internally at Google, is "threadsafe". +static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE; GTEST_DEFINE_string_( death_test_style, @@ -109,8 +122,8 @@ GTEST_DEFINE_string_( "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " - "the '|' characters. This flag is specified if and only if the current " - "process is a sub-process launched for running a thread-safe " + "the '|' characters. This flag is specified if and only if the " + "current process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal @@ -120,7 +133,9 @@ namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA static bool g_in_fast_death_test_child = false; +# endif // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as @@ -128,10 +143,10 @@ static bool g_in_fast_death_test_child = false; // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA - // On Windows, death tests are thread-safe regardless of the value of the - // death_test_style flag. + // On Windows and Fuchsia, death tests are thread-safe regardless of the value + // of the death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else @@ -151,7 +166,7 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return exit_status == exit_code_; @@ -159,19 +174,27 @@ bool ExitedWithCode::operator()(int exit_status) const { return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { +# if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) + { + bool result; + if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { + return result; + } + } +# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA namespace internal { @@ -182,7 +205,7 @@ namespace internal { static std::string ExitSummary(int exit_code) { Message m; -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA m << "Exited with exit status " << exit_code; @@ -198,7 +221,7 @@ static std::string ExitSummary(int exit_code) { m << " (core dumped)"; } # endif -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return m.GetString(); } @@ -209,7 +232,7 @@ bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the @@ -218,13 +241,19 @@ static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; - if (thread_count == 0) + if (thread_count == 0) { msg << "couldn't detect the number of threads."; - else + } else { msg << "detected " << thread_count << " threads."; + } + msg << " See " + "https://github.com/google/googletest/blob/master/googletest/docs/" + "advanced.md#death-tests-and-threads" + << " for more explanation and suggested solutions, especially if" + << " this is the last message you see before your test times out."; return msg.GetString(); } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; @@ -232,6 +261,13 @@ static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; +#if GTEST_OS_FUCHSIA + +// File descriptor used for the pipe in the child process. +static const int kFuchsiaReadPipeFd = 3; + +#endif + // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; @@ -239,8 +275,6 @@ static const char kDeathTestInternalError = 'I'; // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. -// TODO(vladl@google.com): Unify names and possibly values for -// AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an @@ -248,13 +282,13 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. -void DeathTestAbort(const std::string& message) { +static void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); - if (flag != NULL) { + if (flag != nullptr) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); @@ -334,7 +368,7 @@ static void FailFromInternalError(int fd) { // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); - if (info == NULL) { + if (info == nullptr) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } @@ -342,10 +376,11 @@ DeathTest::DeathTest() { // Creates and returns a death test by dispatching to the current // death test factory. -bool DeathTest::Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) { +bool DeathTest::Create(const char* statement, + Matcher matcher, const char* file, + int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( - statement, regex, file, line, test); + statement, std::move(matcher), file, line, test); } const char* DeathTest::LastMessage() { @@ -361,9 +396,9 @@ std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: - DeathTestImpl(const char* a_statement, const RE* a_regex) + DeathTestImpl(const char* a_statement, Matcher matcher) : statement_(a_statement), - regex_(a_regex), + matcher_(std::move(matcher)), spawned_(false), status_(-1), outcome_(IN_PROGRESS), @@ -371,13 +406,12 @@ class DeathTestImpl : public DeathTest { write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. - ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } - void Abort(AbortReason reason); - virtual bool Passed(bool status_ok); + void Abort(AbortReason reason) override; + bool Passed(bool status_ok) override; const char* statement() const { return statement_; } - const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } @@ -395,13 +429,15 @@ class DeathTestImpl : public DeathTest { // case of unexpected codes. void ReadAndInterpretStatusByte(); + // Returns stderr output from the child process. + virtual std::string GetErrorLogs(); + private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; - // The regular expression which test output must match. DeathTestImpl - // doesn't own this object and should not attempt to delete it. - const RE* const regex_; + // A matcher that's expected to match the stderr output by the child process. + Matcher matcher_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. @@ -463,6 +499,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { set_read_fd(-1); } +std::string DeathTestImpl::GetErrorLogs() { + return GetCapturedStderr(); +} + // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then @@ -516,22 +556,21 @@ static ::std::string FormatDeathTestOutput(const ::std::string& output) { // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. -// regex: A regular expression object to be applied to -// the test's captured standard error output; the death test -// fails if it does not match. +// matcher_: A matcher that's expected to match the stderr output by the child +// process. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // -// Returns true iff all of the above conditions are met. Otherwise, the -// first failing condition, in the order given above, is the one that is +// Returns true if and only if all of the above conditions are met. Otherwise, +// the first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; - const std::string error_message = GetCapturedStderr(); + const std::string error_message = GetErrorLogs(); bool success = false; Message buffer; @@ -552,13 +591,15 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case DIED: if (status_ok) { - const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); - if (matched) { + if (matcher_.Matches(error_message)) { success = true; } else { + std::ostringstream stream; + matcher_.DescribeTo(&stream); buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex()->pattern() << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); + << " Expected: " << stream.str() << "\n" + << "Actual msg:\n" + << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" @@ -607,11 +648,11 @@ bool DeathTestImpl::Passed(bool status_ok) { // class WindowsDeathTest : public DeathTestImpl { public: - WindowsDeathTest(const char* a_statement, - const RE* a_regex, - const char* file, - int line) - : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + WindowsDeathTest(const char* a_statement, Matcher matcher, + const char* file, int line) + : DeathTestImpl(a_statement, std::move(matcher)), + file_(file), + line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); @@ -688,7 +729,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); @@ -697,8 +738,8 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. - SECURITY_ATTRIBUTES handles_are_inheritable = { - sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES), + nullptr, TRUE}; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, @@ -709,13 +750,13 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, - TRUE, // The event will automatically reset to non-signaled state. - FALSE, // The initial state is non-signalled. - NULL)); // The even is unnamed. - GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + - info->test_case_name() + "." + info->name(); + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + nullptr)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + @@ -728,10 +769,9 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT - GTEST_DEATH_TEST_CHECK_( - _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, - executable_path, - _MAX_PATH)); + GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr, + executable_path, + _MAX_PATH)); std::string command_line = std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + @@ -752,33 +792,290 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; - GTEST_DEATH_TEST_CHECK_(::CreateProcessA( - executable_path, - const_cast(command_line.c_str()), - NULL, // Retuned process handle is not inheritable. - NULL, // Retuned thread handle is not inheritable. - TRUE, // Child inherits all inheritable handles (for write_handle_). - 0x0, // Default creation flags. - NULL, // Inherit the parent's environment. - UnitTest::GetInstance()->original_working_dir(), - &startup_info, - &process_info) != FALSE); + GTEST_DEATH_TEST_CHECK_( + ::CreateProcessA( + executable_path, const_cast(command_line.c_str()), + nullptr, // Retuned process handle is not inheritable. + nullptr, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + nullptr, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), &startup_info, + &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } -# else // We are not on Windows. + +# elif GTEST_OS_FUCHSIA + +class FuchsiaDeathTest : public DeathTestImpl { + public: + FuchsiaDeathTest(const char* a_statement, Matcher matcher, + const char* file, int line) + : DeathTestImpl(a_statement, std::move(matcher)), + file_(file), + line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + int Wait() override; + TestRole AssumeRole() override; + std::string GetErrorLogs() override; + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // The stderr data captured by the child process. + std::string captured_stderr_; + + zx::process child_process_; + zx::channel exception_channel_; + zx::socket stderr_socket_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { args_.push_back(nullptr); } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + int size() { + return args_.size() - 1; + } + + private: + std::vector args_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int FuchsiaDeathTest::Wait() { + const int kProcessKey = 0; + const int kSocketKey = 1; + const int kExceptionKey = 2; + + if (!spawned()) + return 0; + + // Create a port to wait for socket/task/exception events. + zx_status_t status_zx; + zx::port port; + status_zx = zx::port::create(0, &port); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Register to wait for the child process to terminate. + status_zx = child_process_.wait_async( + port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Register to wait for the socket to be readable or closed. + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Register to wait for an exception. + status_zx = exception_channel_.wait_async( + port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + bool process_terminated = false; + bool socket_closed = false; + do { + zx_port_packet_t packet = {}; + status_zx = port.wait(zx::time::infinite(), &packet); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + if (packet.key == kExceptionKey) { + // Process encountered an exception. Kill it directly rather than + // letting other handlers process the event. We will get a kProcessKey + // event when the process actually terminates. + status_zx = child_process_.kill(); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } else if (packet.key == kProcessKey) { + // Process terminated. + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); + process_terminated = true; + } else if (packet.key == kSocketKey) { + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + if (packet.signal.observed & ZX_SOCKET_READABLE) { + // Read data from the socket. + constexpr size_t kBufferSize = 1024; + do { + size_t old_length = captured_stderr_.length(); + size_t bytes_read = 0; + captured_stderr_.resize(old_length + kBufferSize); + status_zx = stderr_socket_.read( + 0, &captured_stderr_.front() + old_length, kBufferSize, + &bytes_read); + captured_stderr_.resize(old_length + bytes_read); + } while (status_zx == ZX_OK); + if (status_zx == ZX_ERR_PEER_CLOSED) { + socket_closed = true; + } else { + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } + } else { + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED); + socket_closed = true; + } + } + } while (!process_terminated && !socket_closed); + + ReadAndInterpretStatusByte(); + + zx_info_process_t buffer; + status_zx = child_process_.get_info( + ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + GTEST_DEATH_TEST_CHECK_(buffer.exited); + set_status(buffer.return_code); + return status(); +} + +// The AssumeRole process for a Fuchsia death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != nullptr) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(kFuchsiaReadPipeFd); + return EXECUTE_TEST; + } + + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // Build the child process command line. + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + + StreamableToString(line_) + "|" + + StreamableToString(death_test_index); + Arguments args; + args.AddArguments(GetInjectableArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + // Build the pipe for communication with the child. + zx_status_t status; + zx_handle_t child_pipe_handle; + int child_pipe_fd; + status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + set_read_fd(child_pipe_fd); + + // Set the pipe handle for the child. + fdio_spawn_action_t spawn_actions[2] = {}; + fdio_spawn_action_t* add_handle_action = &spawn_actions[0]; + add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; + add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd); + add_handle_action->h.handle = child_pipe_handle; + + // Create a socket pair will be used to receive the child process' stderr. + zx::socket stderr_producer_socket; + status = + zx::socket::create(0, &stderr_producer_socket, &stderr_socket_); + GTEST_DEATH_TEST_CHECK_(status >= 0); + int stderr_producer_fd = -1; + status = + fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd); + GTEST_DEATH_TEST_CHECK_(status >= 0); + + // Make the stderr socket nonblocking. + GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0); + + fdio_spawn_action_t* add_stderr_action = &spawn_actions[1]; + add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD; + add_stderr_action->fd.local_fd = stderr_producer_fd; + add_stderr_action->fd.target_fd = STDERR_FILENO; + + // Create a child job. + zx_handle_t child_job = ZX_HANDLE_INVALID; + status = zx_job_create(zx_job_default(), 0, & child_job); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + zx_policy_basic_t policy; + policy.condition = ZX_POL_NEW_ANY; + policy.policy = ZX_POL_ACTION_ALLOW; + status = zx_job_set_policy( + child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Create an exception channel attached to the |child_job|, to allow + // us to suppress the system default exception handler from firing. + status = + zx_task_create_exception_channel( + child_job, 0, exception_channel_.reset_and_get_address()); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Spawn the child process. + status = fdio_spawn_etc( + child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), nullptr, + 2, spawn_actions, child_process_.reset_and_get_address(), nullptr); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + set_spawned(true); + return OVERSEE_TEST; +} + +std::string FuchsiaDeathTest::GetErrorLogs() { + return captured_stderr_; +} + +#else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. class ForkingDeathTest : public DeathTestImpl { public: - ForkingDeathTest(const char* statement, const RE* regex); + ForkingDeathTest(const char* statement, Matcher matcher); // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); + int Wait() override; protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } @@ -789,9 +1086,9 @@ class ForkingDeathTest : public DeathTestImpl { }; // Constructs a ForkingDeathTest. -ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) - : DeathTestImpl(a_statement, a_regex), - child_pid_(-1) {} +ForkingDeathTest::ForkingDeathTest(const char* a_statement, + Matcher matcher) + : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the @@ -812,9 +1109,9 @@ int ForkingDeathTest::Wait() { // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: - NoExecDeathTest(const char* a_statement, const RE* a_regex) : - ForkingDeathTest(a_statement, a_regex) { } - virtual TestRole AssumeRole(); + NoExecDeathTest(const char* a_statement, Matcher matcher) + : ForkingDeathTest(a_statement, std::move(matcher)) {} + TestRole AssumeRole() override; }; // The AssumeRole process for a fork-and-run death test. It implements a @@ -867,14 +1164,21 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: - ExecDeathTest(const char* a_statement, const RE* a_regex, - const char* file, int line) : - ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } - virtual TestRole AssumeRole(); + ExecDeathTest(const char* a_statement, Matcher matcher, + const char* file, int line) + : ForkingDeathTest(a_statement, std::move(matcher)), + file_(file), + line_(line) {} + TestRole AssumeRole() override; + private: - static ::std::vector - GetArgvsForDeathTestChildProcess() { - ::std::vector args = GetInjectableArgvs(); + static ::std::vector GetArgvsForDeathTestChildProcess() { + ::std::vector args = GetInjectableArgvs(); +# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) + ::std::vector extra_args = + GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); + args.insert(args.end(), extra_args.begin(), extra_args.end()); +# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) return args; } // The name of the file in which the death test is located. @@ -886,9 +1190,7 @@ class ExecDeathTest : public ForkingDeathTest { // Utility class for accumulating command-line arguments. class Arguments { public: - Arguments() { - args_.push_back(NULL); - } + Arguments() { args_.push_back(nullptr); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); @@ -970,6 +1272,7 @@ static int ExecDeathTestChildMain(void* child_arg) { } # endif // !GTEST_OS_QNX +# if GTEST_HAS_CLONE // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive @@ -979,18 +1282,26 @@ static int ExecDeathTestChildMain(void* child_arg) { // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. -void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; -void StackLowerThanAddress(const void* ptr, bool* result) { +static void StackLowerThanAddress(const void* ptr, + bool* result) GTEST_NO_INLINE_; +// HWAddressSanitizer add a random tag to the MSB of the local variable address, +// making comparison result unpredictable. +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +static void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } -bool StackGrowsDown() { +// Make sure AddressSanitizer does not tamper with the stack here. +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +static bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } +# endif // GTEST_HAS_CLONE // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The @@ -1028,7 +1339,8 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. - child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); + child_pid = + spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); @@ -1052,9 +1364,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); - const size_t stack_size = getpagesize(); + const auto stack_size = static_cast(getpagesize()); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. - void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); @@ -1068,8 +1380,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); - GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && - reinterpret_cast(stack_top) % kMaxStackAlignment == 0); + GTEST_DEATH_TEST_CHECK_( + static_cast(stack_size) > kMaxStackAlignment && + reinterpret_cast(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); @@ -1086,7 +1399,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { # endif // GTEST_OS_QNX # if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( - sigaction(SIGPROF, &saved_sigprof_action, NULL)); + sigaction(SIGPROF, &saved_sigprof_action, nullptr)); # endif // GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_(child_pid != -1); @@ -1104,7 +1417,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } @@ -1115,9 +1428,9 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" - + info->test_case_name() + "." + info->name(); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" @@ -1150,7 +1463,8 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. -bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, +bool DefaultDeathTestFactory::Create(const char* statement, + Matcher matcher, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); @@ -1159,7 +1473,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, const int death_test_index = impl->current_test_info() ->increment_death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message( "Death test count (" + StreamableToString(death_test_index) @@ -1170,7 +1484,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { - *test = NULL; + *test = nullptr; return true; } } @@ -1179,15 +1493,22 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { - *test = new WindowsDeathTest(statement, regex, file, line); + *test = new WindowsDeathTest(statement, std::move(matcher), file, line); + } + +# elif GTEST_OS_FUCHSIA + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line); } # else if (GTEST_FLAG(death_test_style) == "threadsafe") { - *test = new ExecDeathTest(statement, regex, file, line); + *test = new ExecDeathTest(statement, std::move(matcher), file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { - *test = new NoExecDeathTest(statement, regex); + *test = new NoExecDeathTest(statement, std::move(matcher)); } # endif // GTEST_OS_WINDOWS @@ -1202,31 +1523,11 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, return true; } -// Splits a given string on a given delimiter, populating a given -// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have -// ::std::string, so we can use it here. -static void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest) { - ::std::vector< ::std::string> parsed; - ::std::string::size_type pos = 0; - while (::testing::internal::AlwaysTrue()) { - const ::std::string::size_type colon = str.find(delimiter, pos); - if (colon == ::std::string::npos) { - parsed.push_back(str.substr(pos)); - break; - } else { - parsed.push_back(str.substr(pos, colon - pos)); - pos = colon + 1; - } - } - dest->swap(parsed); -} - # if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. -int GetStatusFileDescriptor(unsigned int parent_process_id, +static int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, @@ -1237,15 +1538,13 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, StreamableToString(parent_process_id)); } - // TODO(vladl@google.com): Replace the following check with a - // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; - // The newly initialized handle is accessible only in in the parent + // The newly initialized handle is accessible only in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, @@ -1294,7 +1593,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { - if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + if (GTEST_FLAG(internal_run_death_test) == "") return nullptr; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. @@ -1322,6 +1621,16 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); + +# elif GTEST_OS_FUCHSIA + + if (fields.size() != 3 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + # else if (fields.size() != 4 diff --git a/test/gtest/src/gtest-filepath.cc b/test/gtest/src/gtest-filepath.cc index 6be58b6fca..bd7b99ff03 100644 --- a/test/gtest/src/gtest-filepath.cc +++ b/test/gtest/src/gtest-filepath.cc @@ -26,28 +26,25 @@ // 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. -// -// Authors: keith.ray@gmail.com (Keith Ray) -#include "gtest/gtest-message.h" #include "gtest/internal/gtest-filepath.h" -#include "gtest/internal/gtest-port.h" #include +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-message.h" #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include # include -#elif GTEST_OS_SYMBIAN -// Symbian OpenC has PATH_MAX in sys/syslimits.h -# include #else # include # include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE +#include "gtest/internal/gtest-string.h" + #if GTEST_OS_WINDOWS # define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) @@ -58,8 +55,6 @@ # define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS -#include "gtest/internal/gtest-string.h" - namespace testing { namespace internal { @@ -70,7 +65,6 @@ namespace internal { // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; -const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use @@ -84,7 +78,6 @@ const char kCurrentDirectoryString[] = ".\\"; # endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; -const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS @@ -99,16 +92,24 @@ static bool IsPathSeparator(char c) { // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE - // Windows CE doesn't have a current directory, so we just return +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || ARDUINO || defined(ESP_PLATFORM) + // These platforms do not have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); + return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); + char* result = getcwd(cwd, sizeof(cwd)); +# if GTEST_OS_NACL + // getcwd will likely fail in NaCl due to the sandbox, so return something + // reasonable. The user may have provided a shim implementation for getcwd, + // however, so fallback only when failure is detected. + return FilePath(result == nullptr ? kCurrentDirectoryString : cwd); +# endif // GTEST_OS_NACL + return FilePath(result == nullptr ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } @@ -125,7 +126,7 @@ FilePath FilePath::RemoveExtension(const char* extension) const { return *this; } -// Returns a pointer to the last occurence of a valid path separator in +// Returns a pointer to the last occurrence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { @@ -133,8 +134,8 @@ const char* FilePath::FindLastPathSeparator() const { #if GTEST_HAS_ALT_PATH_SEP_ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); // Comparing two pointers of which only one is NULL is undefined. - if (last_alt_sep != NULL && - (last_sep == NULL || last_alt_sep > last_sep)) { + if (last_alt_sep != nullptr && + (last_sep == nullptr || last_alt_sep > last_sep)) { return last_alt_sep; } #endif @@ -162,7 +163,7 @@ FilePath FilePath::RemoveFileName() const { const char* const last_sep = FindLastPathSeparator(); std::string dir; if (last_sep) { - dir = std::string(c_str(), last_sep + 1 - c_str()); + dir = std::string(c_str(), static_cast(last_sep + 1 - c_str())); } else { dir = kCurrentDirectoryString; } @@ -247,9 +248,6 @@ bool FilePath::DirectoryExists() const { // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS - // TODO(wan@google.com): on Windows a network share like - // \\server\share can be a root directory, although it cannot be the - // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); @@ -321,7 +319,7 @@ bool FilePath::CreateFolder() const { #if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); - int result = CreateDirectory(unicode, NULL) ? 0 : -1; + int result = CreateDirectory(unicode, nullptr) ? 0 : -1; delete [] unicode; #elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); @@ -347,9 +345,8 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". -// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { - if (pathname_.c_str() == NULL) { + if (pathname_.c_str() == nullptr) { pathname_ = ""; return; } diff --git a/test/gtest/src/gtest-internal-inl.h b/test/gtest/src/gtest-internal-inl.h index 35df303cca..8ed70daab0 100644 --- a/test/gtest/src/gtest-internal-inl.h +++ b/test/gtest/src/gtest-internal-inl.h @@ -27,24 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Utility functions and classes used by the Google C++ testing framework. -// -// Author: wan@google.com (Zhanyong Wan) -// +// Utility functions and classes used by the Google C++ testing framework.// // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ -// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is -// part of Google Test's implementation; otherwise it's undefined. -#if !GTEST_IMPLEMENTATION_ -// A user is trying to include this from his code - just say no. -# error "gtest-internal-inl.h is part of Google Test's internal implementation." -# error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION_ - #ifndef _WIN32_WCE # include #endif // !_WIN32_WCE @@ -53,6 +42,7 @@ #include // For memmove. #include +#include #include #include @@ -67,9 +57,12 @@ # include // NOLINT #endif // GTEST_OS_WINDOWS -#include "gtest/gtest.h" // NOLINT +#include "gtest/gtest.h" #include "gtest/gtest-spi.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // Declares the flags. @@ -94,24 +87,26 @@ const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; +const char kPrintUTF8Flag[] = "print_utf8"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; +const char kFlagfileFlag[] = "flagfile"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); -// Returns true iff Google Test should use colors in the output. +// Returns true if and only if Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. @@ -173,6 +168,7 @@ class GTestFlagSaver { list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); + print_utf8_ = GTEST_FLAG(print_utf8); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); @@ -194,6 +190,7 @@ class GTestFlagSaver { GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(print_utf8) = print_utf8_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; @@ -215,6 +212,7 @@ class GTestFlagSaver { bool list_tests_; std::string output_; bool print_time_; + bool print_utf8_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; @@ -233,7 +231,7 @@ GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number @@ -268,8 +266,8 @@ GTEST_API_ bool ShouldShard(const char* total_shards_str, GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); @@ -300,7 +298,8 @@ void ForEach(const Container& c, Functor functor) { // in range [0, v.size()). template inline E GetElementOr(const std::vector& v, int i, E default_value) { - return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; + return (i < 0 || i >= static_cast(v.size())) ? default_value + : v[static_cast(i)]; } // Performs an in-place shuffle of a range of the vector's elements. @@ -322,8 +321,11 @@ void ShuffleRange(internal::Random* random, int begin, int end, // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; - const int selected = begin + random->Generate(range_width); - std::swap((*v)[selected], (*v)[last_in_range]); + const int selected = + begin + + static_cast(random->Generate(static_cast(range_width))); + std::swap((*v)[static_cast(selected)], + (*v)[static_cast(last_in_range)]); } } @@ -350,7 +352,7 @@ class TestPropertyKeyIs { // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} - // Returns true iff the test name of test property matches on key_. + // Returns true if and only if the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return test_property.key() == key_; } @@ -383,17 +385,17 @@ class GTEST_API_ UnitTestOptions { // Functions for processing the gtest_filter flag. - // Returns true iff the wildcard pattern matches the string. The - // first ':' or '\0' character in pattern marks the end of it. + // Returns true if and only if the wildcard pattern matches the string. + // The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); - // Returns true iff the user-specified filter matches the test case - // name and the test name. - static bool FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name); + // Returns true if and only if the user-specified filter matches the test + // suite name and the test name. + static bool FilterMatchesTest(const std::string& test_suite_name, + const std::string& test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. @@ -425,13 +427,17 @@ class OsStackTraceGetterInterface { // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. - virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; + virtual std::string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; @@ -439,25 +445,21 @@ class OsStackTraceGetterInterface { // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: - OsStackTraceGetter() : caller_frame_(NULL) {} - - virtual string CurrentStackTrace(int max_depth, int skip_count) - GTEST_LOCK_EXCLUDED_(mutex_); + OsStackTraceGetter() {} - virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); - - // This string is inserted in place of stack frames that are part of - // Google Test's implementation. - static const char* const kElidedFramesMarker; + std::string CurrentStackTrace(int max_depth, int skip_count) override; + void UponLeavingGTest() override; private: - Mutex mutex_; // protects all internal state +#if GTEST_HAS_ABSL + Mutex mutex_; // Protects all internal state. // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() - // and any calls to CurrentStackTrace() from within the user code. - void* caller_frame_; + // and any calls to the stack trace code from within the user code. + void* caller_frame_ = nullptr; +#endif // GTEST_HAS_ABSL GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; @@ -477,7 +479,7 @@ class DefaultGlobalTestPartResultReporter explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult& result) override; private: UnitTestImpl* const unit_test_; @@ -493,7 +495,7 @@ class DefaultPerThreadTestPartResultReporter explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult& result) override; private: UnitTestImpl* const unit_test_; @@ -531,22 +533,25 @@ class GTEST_API_ UnitTestImpl { void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); - // Gets the number of successful test cases. - int successful_test_case_count() const; + // Gets the number of successful test suites. + int successful_test_suite_count() const; - // Gets the number of failed test cases. - int failed_test_case_count() const; + // Gets the number of failed test suites. + int failed_test_suite_count() const; - // Gets the number of all test cases. - int total_test_case_count() const; + // Gets the number of all test suites. + int total_test_suite_count() const; - // Gets the number of all test cases that contain at least one test + // Gets the number of all test suites that contain at least one test // that should run. - int test_case_to_run_count() const; + int test_suite_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; + // Gets the number of skipped tests. + int skipped_test_count() const; + // Gets the number of failed tests. int failed_test_count() const; @@ -572,27 +577,33 @@ class GTEST_API_ UnitTestImpl { // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } - // Returns true iff the unit test passed (i.e. all test cases passed). + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). bool Passed() const { return !Failed(); } - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). bool Failed() const { - return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed(); } - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[i]; + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite* GetTestSuite(int i) const { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast(i)]; } - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i) { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[index]; + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* GetTestCase(int i) const { return GetTestSuite(i); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite* GetMutableSuiteCase(int i) { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast(index)]; } // Provides access to the event listener list. @@ -629,30 +640,38 @@ class GTEST_API_ UnitTestImpl { // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; - // Finds and returns a TestCase with the given name. If one doesn't + // Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // - // test_case_name: name of the test case + // test_suite_name: name of the test suite // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase* GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + TestCase* GetTestCase(const char* test_case_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + return GetTestSuite(test_case_name, type_param, set_up_tc, tear_down_tc); + } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Adds a TestInfo to the unit test. // // Arguments: // - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite // test_info: the TestInfo object - void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, + void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, TestInfo* test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program @@ -667,23 +686,20 @@ class GTEST_API_ UnitTestImpl { << "Failed to get the current working directory."; } - GetTestCase(test_info->test_case_name(), - test_info->type_param(), - set_up_tc, - tear_down_tc)->AddTestInfo(test_info); + GetTestSuite(test_info->test_suite_name(), test_info->type_param(), + set_up_tc, tear_down_tc) + ->AddTestInfo(test_info); } -#if GTEST_HAS_PARAM_TEST - // Returns ParameterizedTestCaseRegistry object used to keep track of + // Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() { return parameterized_test_registry_; } -#endif // GTEST_HAS_PARAM_TEST - // Sets the TestCase object for the test that's currently running. - void set_current_test_case(TestCase* a_current_test_case) { - current_test_case_ = a_current_test_case; + // Sets the TestSuite object for the test that's currently running. + void set_current_test_suite(TestSuite* a_current_test_suite) { + current_test_suite_ = a_current_test_suite; } // Sets the TestInfo object for the test that's currently running. If @@ -694,7 +710,7 @@ class GTEST_API_ UnitTestImpl { } // Registers all parameterized tests defined using TEST_P and - // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // INSTANTIATE_TEST_SUITE_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has guards // protecting from registering the tests more then once. If // value-parameterized tests are disabled, RegisterParameterizedTests is @@ -709,7 +725,7 @@ class GTEST_API_ UnitTestImpl { // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { - ForEach(test_cases_, TestCase::ClearTestCaseResult); + ForEach(test_suites_, TestSuite::ClearTestSuiteResult); } // Clears the results of ad-hoc test assertions. @@ -718,7 +734,7 @@ class GTEST_API_ UnitTestImpl { } // Adds a TestProperty to the current TestResult object when invoked in a - // context of a test or a test case, or to the global property set. If the + // context of a test or a test suite, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. void RecordProperty(const TestProperty& test_property); @@ -730,7 +746,7 @@ class GTEST_API_ UnitTestImpl { // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the - // result in each TestCase and TestInfo object. + // result in each TestSuite and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. @@ -739,7 +755,7 @@ class GTEST_API_ UnitTestImpl { // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); - const TestCase* current_test_case() const { return current_test_case_; } + const TestSuite* current_test_suite() const { return current_test_suite_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } @@ -800,11 +816,11 @@ class GTEST_API_ UnitTestImpl { // Gets the random number generator. internal::Random* random() { return &random_; } - // Shuffles all test cases, and the tests within each test case, + // Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void ShuffleTests(); - // Restores the test cases and tests to their order before the first shuffle. + // Restores the test suites and tests to their order before the first shuffle. void UnshuffleTests(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment @@ -844,33 +860,31 @@ class GTEST_API_ UnitTestImpl { // before/after the tests are run. std::vector environments_; - // The vector of TestCases in their original order. It owns the + // The vector of TestSuites in their original order. It owns the // elements in the vector. - std::vector test_cases_; + std::vector test_suites_; - // Provides a level of indirection for the test case list to allow - // easy shuffling and restoring the test case order. The i-th - // element of this vector is the index of the i-th test case in the + // Provides a level of indirection for the test suite list to allow + // easy shuffling and restoring the test suite order. The i-th + // element of this vector is the index of the i-th test suite in the // shuffled order. - std::vector test_case_indices_; + std::vector test_suite_indices_; -#if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. - internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + internal::ParameterizedTestSuiteRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; -#endif // GTEST_HAS_PARAM_TEST - // Index of the last death test case registered. Initially -1. - int last_death_test_case_; + // Index of the last death test suite registered. Initially -1. + int last_death_test_suite_; - // This points to the TestCase for the currently running test. It - // changes as Google Test goes through one test case after another. + // This points to the TestSuite for the currently running test. It + // changes as Google Test goes through one test suite after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. - TestCase* current_test_case_; + TestSuite* current_test_suite_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When @@ -898,7 +912,7 @@ class GTEST_API_ UnitTestImpl { // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; - // True iff PostFlagParsingInit() has been called. + // True if and only if PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. @@ -917,8 +931,8 @@ class GTEST_API_ UnitTestImpl { #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. - internal::scoped_ptr internal_run_death_test_flag_; - internal::scoped_ptr death_test_factory_; + std::unique_ptr internal_run_death_test_flag_; + std::unique_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. @@ -968,32 +982,6 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // platform. GTEST_API_ std::string GetLastErrnoDescription(); -# if GTEST_OS_WINDOWS -// Provides leak-safe Windows kernel handle ownership. -class AutoHandle { - public: - AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} - explicit AutoHandle(HANDLE handle) : handle_(handle) {} - - ~AutoHandle() { Reset(); } - - HANDLE Get() const { return handle_; } - void Reset() { Reset(INVALID_HANDLE_VALUE); } - void Reset(HANDLE handle) { - if (handle != handle_) { - if (handle_ != INVALID_HANDLE_VALUE) - ::CloseHandle(handle_); - handle_ = handle; - } - } - - private: - HANDLE handle_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); -}; -# endif // GTEST_OS_WINDOWS - // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use @@ -1027,8 +1015,6 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { const bool parse_success = *end == '\0' && errno == 0; - // TODO(vladl@google.com): Convert this to compile time assertion when it is - // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); @@ -1075,37 +1061,35 @@ class StreamingListener : public EmptyTestEventListener { virtual ~AbstractSocketWriter() {} // Sends a string to the socket. - virtual void Send(const string& message) = 0; + virtual void Send(const std::string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. - void SendLn(const string& message) { - Send(message + "\n"); - } + void SendLn(const std::string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: - SocketWriter(const string& host, const string& port) + SocketWriter(const std::string& host, const std::string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } - virtual ~SocketWriter() { + ~SocketWriter() override { if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. - virtual void Send(const string& message) { + void Send(const std::string& message) override { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; - const int len = static_cast(message.length()); - if (write(sockfd_, message.c_str(), len) != len) { + const auto len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != static_cast(len)) { GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " << host_name_ << ":" << port_num_; @@ -1117,7 +1101,7 @@ class StreamingListener : public EmptyTestEventListener { void MakeConnection(); // Closes the socket. - void CloseConnection() { + void CloseConnection() override { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; @@ -1126,26 +1110,28 @@ class StreamingListener : public EmptyTestEventListener { } int sockfd_; // socket file descriptor - const string host_name_; - const string port_num_; + const std::string host_name_; + const std::string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static string UrlEncode(const char* str); + static std::string UrlEncode(const char* str); - StreamingListener(const string& host, const string& port) - : socket_writer_(new SocketWriter(host, port)) { Start(); } + StreamingListener(const std::string& host, const std::string& port) + : socket_writer_(new SocketWriter(host, port)) { + Start(); + } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } - void OnTestProgramStart(const UnitTest& /* unit_test */) { + void OnTestProgramStart(const UnitTest& /* unit_test */) override { SendLn("event=TestProgramStart"); } - void OnTestProgramEnd(const UnitTest& unit_test) { + void OnTestProgramEnd(const UnitTest& unit_test) override { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); @@ -1154,42 +1140,47 @@ class StreamingListener : public EmptyTestEventListener { socket_writer_->CloseConnection(); } - void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + void OnTestIterationStart(const UnitTest& /* unit_test */, + int iteration) override { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } - void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + void OnTestIterationEnd(const UnitTest& unit_test, + int /* iteration */) override { SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + "ms"); } - void OnTestCaseStart(const TestCase& test_case) { + // Note that "event=TestCaseStart" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseStart(const TestCase& test_case) override { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } - void OnTestCaseEnd(const TestCase& test_case) { - SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) - + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) - + "ms"); + // Note that "event=TestCaseEnd" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseEnd(const TestCase& test_case) override { + SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + + "ms"); } - void OnTestStart(const TestInfo& test_info) { + void OnTestStart(const TestInfo& test_info) override { SendLn(std::string("event=TestStart&name=") + test_info.name()); } - void OnTestEnd(const TestInfo& test_info) { + void OnTestEnd(const TestInfo& test_info) override { SendLn("event=TestEnd&passed=" + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } - void OnTestPartResult(const TestPartResult& test_part_result) { + void OnTestPartResult(const TestPartResult& test_part_result) override { const char* file_name = test_part_result.file_name(); - if (file_name == NULL) - file_name = ""; + if (file_name == nullptr) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); @@ -1197,15 +1188,15 @@ class StreamingListener : public EmptyTestEventListener { private: // Sends the given message and a newline to the socket. - void SendLn(const string& message) { socket_writer_->SendLn(message); } + void SendLn(const std::string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } - string FormatBool(bool value) { return value ? "1" : "0"; } + std::string FormatBool(bool value) { return value ? "1" : "0"; } - const scoped_ptr socket_writer_; + const std::unique_ptr socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener @@ -1215,4 +1206,6 @@ class StreamingListener : public EmptyTestEventListener { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/test/gtest/src/gtest-matchers.cc b/test/gtest/src/gtest-matchers.cc new file mode 100644 index 0000000000..7d2fb6851e --- /dev/null +++ b/test/gtest/src/gtest-matchers.cc @@ -0,0 +1,97 @@ +// Copyright 2007, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-matchers.h" + +#include + +namespace testing { + +// Constructs a matcher that matches a const std::string& whose value is +// equal to s. +Matcher::Matcher(const std::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a const std::string& whose value is +// equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a std::string whose value is equal to +// s. +Matcher::Matcher(const std::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a std::string whose value is equal to +// s. +Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } + +#if GTEST_HAS_ABSL +// Constructs a matcher that matches a const absl::string_view& whose value is +// equal to s. +Matcher::Matcher(const std::string& s) { + *this = Eq(s); +} + +// Constructs a matcher that matches a const absl::string_view& whose value is +// equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a const absl::string_view& whose value is +// equal to s. +Matcher::Matcher(absl::string_view s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a absl::string_view whose value is equal to +// s. +Matcher::Matcher(const std::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a absl::string_view whose value is equal to +// s. +Matcher::Matcher(const char* s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a absl::string_view whose value is equal to +// s. +Matcher::Matcher(absl::string_view s) { + *this = Eq(std::string(s)); +} +#endif // GTEST_HAS_ABSL + +} // namespace testing diff --git a/test/gtest/src/gtest-port.cc b/test/gtest/src/gtest-port.cc index 0c4df5f29a..fc5ba6becc 100644 --- a/test/gtest/src/gtest-port.cc +++ b/test/gtest/src/gtest-port.cc @@ -26,24 +26,28 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + #include "gtest/internal/gtest-port.h" #include -#include #include +#include #include +#include +#include -#if GTEST_OS_WINDOWS_MOBILE -# include // For TerminateProcess() -#elif GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +# include # include # include +# include // Used in ThreadLocal. +# ifdef _MSC_VER +# include +# endif // _MSC_VER #else # include -#endif // GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC # include @@ -51,24 +55,35 @@ # include #endif // GTEST_OS_MAC +#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD || GTEST_OS_OPENBSD +# include +# if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +# include +# endif +#endif + #if GTEST_OS_QNX # include +# include # include #endif // GTEST_OS_QNX +#if GTEST_OS_AIX +# include +# include +#endif // GTEST_OS_AIX + +#if GTEST_OS_FUCHSIA +# include +# include +#endif // GTEST_OS_FUCHSIA + #include "gtest/gtest-spi.h" #include "gtest/gtest-message.h" #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { @@ -82,10 +97,31 @@ const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER -#if GTEST_OS_MAC +#if GTEST_OS_LINUX + +namespace { +template +T ReadProcFileField(const std::string& filename, int field) { + std::string dummy; + std::ifstream file(filename.c_str()); + while (field-- > 0) { + file >> dummy; + } + T output = 0; + file >> output; + return output; +} +} // namespace + +// Returns the number of active threads, or 0 when there is an error. +size_t GetThreadCount() { + const std::string filename = + (Message() << "/proc/" << getpid() << "/stat").GetString(); + return ReadProcFileField(filename, 19); +} + +#elif GTEST_OS_MAC -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; @@ -103,6 +139,81 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD + +#if GTEST_OS_NETBSD +#undef KERN_PROC +#define KERN_PROC KERN_PROC2 +#define kinfo_proc kinfo_proc2 +#endif + +#if GTEST_OS_DRAGONFLY +#define KP_NLWP(kp) (kp.kp_nthreads) +#elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +#define KP_NLWP(kp) (kp.ki_numthreads) +#elif GTEST_OS_NETBSD +#define KP_NLWP(kp) (kp.p_nlwps) +#endif + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID, + getpid(), +#if GTEST_OS_NETBSD + sizeof(struct kinfo_proc), + 1, +#endif + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + struct kinfo_proc info; + size_t size = sizeof(info); + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + return static_cast(KP_NLWP(info)); +} +#elif GTEST_OS_OPENBSD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID | KERN_PROC_SHOW_THREADS, + getpid(), + sizeof(struct kinfo_proc), + 0, + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + + // get number of structs + size_t size; + if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { + return 0; + } + mib[5] = size / mib[4]; + + // populate array of structs + struct kinfo_proc info[mib[5]]; + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + + // exclude empty members + int nthreads = 0; + for (int i = 0; i < size / mib[4]; i++) { + if (info[i].p_tid != -1) + nthreads++; + } + return nthreads; +} + #elif GTEST_OS_QNX // Returns the number of threads running in the process, or 0 to indicate that @@ -114,7 +225,7 @@ size_t GetThreadCount() { } procfs_info process_info; const int status = - devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); + devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), nullptr); close(fd); if (status == EOK) { return static_cast(process_info.num_threads); @@ -123,6 +234,38 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_AIX + +size_t GetThreadCount() { + struct procentry64 entry; + pid_t pid = getpid(); + int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1); + if (status == 1) { + return entry.pi_thcount; + } else { + return 0; + } +} + +#elif GTEST_OS_FUCHSIA + +size_t GetThreadCount() { + int dummy_buffer; + size_t avail; + zx_status_t status = zx_object_get_info( + zx_process_self(), + ZX_INFO_PROCESS_THREADS, + &dummy_buffer, + 0, + nullptr, + &avail); + if (status == ZX_OK) { + return avail; + } else { + return 0; + } +} + #else size_t GetThreadCount() { @@ -131,7 +274,430 @@ size_t GetThreadCount() { return 0; } -#endif // GTEST_OS_MAC +#endif // GTEST_OS_LINUX + +#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS + +void SleepMilliseconds(int n) { + ::Sleep(static_cast(n)); +} + +AutoHandle::AutoHandle() + : handle_(INVALID_HANDLE_VALUE) {} + +AutoHandle::AutoHandle(Handle handle) + : handle_(handle) {} + +AutoHandle::~AutoHandle() { + Reset(); +} + +AutoHandle::Handle AutoHandle::Get() const { + return handle_; +} + +void AutoHandle::Reset() { + Reset(INVALID_HANDLE_VALUE); +} + +void AutoHandle::Reset(HANDLE handle) { + // Resetting with the same handle we already own is invalid. + if (handle_ != handle) { + if (IsCloseable()) { + ::CloseHandle(handle_); + } + handle_ = handle; + } else { + GTEST_CHECK_(!IsCloseable()) + << "Resetting a valid handle to itself is likely a programmer error " + "and thus not allowed."; + } +} + +bool AutoHandle::IsCloseable() const { + // Different Windows APIs may use either of these values to represent an + // invalid handle. + return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE; +} + +Notification::Notification() + : event_(::CreateEvent(nullptr, // Default security attributes. + TRUE, // Do not reset automatically. + FALSE, // Initially unset. + nullptr)) { // Anonymous event. + GTEST_CHECK_(event_.Get() != nullptr); +} + +void Notification::Notify() { + GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); +} + +void Notification::WaitForNotification() { + GTEST_CHECK_( + ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); +} + +Mutex::Mutex() + : owner_thread_id_(0), + type_(kDynamic), + critical_section_init_phase_(0), + critical_section_(new CRITICAL_SECTION) { + ::InitializeCriticalSection(critical_section_); +} + +Mutex::~Mutex() { + // Static mutexes are leaked intentionally. It is not thread-safe to try + // to clean them up. + if (type_ == kDynamic) { + ::DeleteCriticalSection(critical_section_); + delete critical_section_; + critical_section_ = nullptr; + } +} + +void Mutex::Lock() { + ThreadSafeLazyInit(); + ::EnterCriticalSection(critical_section_); + owner_thread_id_ = ::GetCurrentThreadId(); +} + +void Mutex::Unlock() { + ThreadSafeLazyInit(); + // We don't protect writing to owner_thread_id_ here, as it's the + // caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_thread_id_ = 0; + ::LeaveCriticalSection(critical_section_); +} + +// Does nothing if the current thread holds the mutex. Otherwise, crashes +// with high probability. +void Mutex::AssertHeld() { + ThreadSafeLazyInit(); + GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) + << "The current thread is not holding the mutex @" << this; +} + +namespace { + +#ifdef _MSC_VER +// Use the RAII idiom to flag mem allocs that are intentionally never +// deallocated. The motivation is to silence the false positive mem leaks +// that are reported by the debug version of MS's CRT which can only detect +// if an alloc is missing a matching deallocation. +// Example: +// MemoryIsNotDeallocated memory_is_not_deallocated; +// critical_section_ = new CRITICAL_SECTION; +// +class MemoryIsNotDeallocated +{ + public: + MemoryIsNotDeallocated() : old_crtdbg_flag_(0) { + old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT + // doesn't report mem leak if there's no matching deallocation. + _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF); + } + + ~MemoryIsNotDeallocated() { + // Restore the original _CRTDBG_ALLOC_MEM_DF flag + _CrtSetDbgFlag(old_crtdbg_flag_); + } + + private: + int old_crtdbg_flag_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated); +}; +#endif // _MSC_VER + +} // namespace + +// Initializes owner_thread_id_ and critical_section_ in static mutexes. +void Mutex::ThreadSafeLazyInit() { + // Dynamic mutexes are initialized in the constructor. + if (type_ == kStatic) { + switch ( + ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { + case 0: + // If critical_section_init_phase_ was 0 before the exchange, we + // are the first to test it and need to perform the initialization. + owner_thread_id_ = 0; + { + // Use RAII to flag that following mem alloc is never deallocated. +#ifdef _MSC_VER + MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER + critical_section_ = new CRITICAL_SECTION; + } + ::InitializeCriticalSection(critical_section_); + // Updates the critical_section_init_phase_ to 2 to signal + // initialization complete. + GTEST_CHECK_(::InterlockedCompareExchange( + &critical_section_init_phase_, 2L, 1L) == + 1L); + break; + case 1: + // Somebody else is already initializing the mutex; spin until they + // are done. + while (::InterlockedCompareExchange(&critical_section_init_phase_, + 2L, + 2L) != 2L) { + // Possibly yields the rest of the thread's time slice to other + // threads. + ::Sleep(0); + } + break; + + case 2: + break; // The mutex is already initialized and ready for use. + + default: + GTEST_CHECK_(false) + << "Unexpected value of critical_section_init_phase_ " + << "while initializing a static mutex."; + } + } +} + +namespace { + +class ThreadWithParamSupport : public ThreadWithParamBase { + public: + static HANDLE CreateThread(Runnable* runnable, + Notification* thread_can_start) { + ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); + DWORD thread_id; + HANDLE thread_handle = ::CreateThread( + nullptr, // Default security. + 0, // Default stack size. + &ThreadWithParamSupport::ThreadMain, + param, // Parameter to ThreadMainStatic + 0x0, // Default creation flags. + &thread_id); // Need a valid pointer for the call to work under Win98. + GTEST_CHECK_(thread_handle != nullptr) + << "CreateThread failed with error " << ::GetLastError() << "."; + if (thread_handle == nullptr) { + delete param; + } + return thread_handle; + } + + private: + struct ThreadMainParam { + ThreadMainParam(Runnable* runnable, Notification* thread_can_start) + : runnable_(runnable), + thread_can_start_(thread_can_start) { + } + std::unique_ptr runnable_; + // Does not own. + Notification* thread_can_start_; + }; + + static DWORD WINAPI ThreadMain(void* ptr) { + // Transfers ownership. + std::unique_ptr param(static_cast(ptr)); + if (param->thread_can_start_ != nullptr) + param->thread_can_start_->WaitForNotification(); + param->runnable_->Run(); + return 0; + } + + // Prohibit instantiation. + ThreadWithParamSupport(); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); +}; + +} // namespace + +ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, + Notification* thread_can_start) + : thread_(ThreadWithParamSupport::CreateThread(runnable, + thread_can_start)) { +} + +ThreadWithParamBase::~ThreadWithParamBase() { + Join(); +} + +void ThreadWithParamBase::Join() { + GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) + << "Failed to join the thread with error " << ::GetLastError() << "."; +} + +// Maps a thread to a set of ThreadIdToThreadLocals that have values +// instantiated on that thread and notifies them when the thread exits. A +// ThreadLocal instance is expected to persist until all threads it has +// values on have terminated. +class ThreadLocalRegistryImpl { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + DWORD current_thread = ::GetCurrentThreadId(); + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(current_thread); + if (thread_local_pos == thread_to_thread_locals->end()) { + thread_local_pos = thread_to_thread_locals->insert( + std::make_pair(current_thread, ThreadLocalValues())).first; + StartWatcherThreadFor(current_thread); + } + ThreadLocalValues& thread_local_values = thread_local_pos->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos == thread_local_values.end()) { + value_pos = + thread_local_values + .insert(std::make_pair( + thread_local_instance, + std::shared_ptr( + thread_local_instance->NewValueForCurrentThread()))) + .first; + } + return value_pos->second.get(); + } + + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + std::vector > value_holders; + // Clean up the ThreadLocalValues data structure while holding the lock, but + // defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + for (ThreadIdToThreadLocals::iterator it = + thread_to_thread_locals->begin(); + it != thread_to_thread_locals->end(); + ++it) { + ThreadLocalValues& thread_local_values = it->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos != thread_local_values.end()) { + value_holders.push_back(value_pos->second); + thread_local_values.erase(value_pos); + // This 'if' can only be successful at most once, so theoretically we + // could break out of the loop here, but we don't bother doing so. + } + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + static void OnThreadExit(DWORD thread_id) { + GTEST_CHECK_(thread_id != 0) << ::GetLastError(); + std::vector > value_holders; + // Clean up the ThreadIdToThreadLocals data structure while holding the + // lock, but defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(thread_id); + if (thread_local_pos != thread_to_thread_locals->end()) { + ThreadLocalValues& thread_local_values = thread_local_pos->second; + for (ThreadLocalValues::iterator value_pos = + thread_local_values.begin(); + value_pos != thread_local_values.end(); + ++value_pos) { + value_holders.push_back(value_pos->second); + } + thread_to_thread_locals->erase(thread_local_pos); + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + private: + // In a particular thread, maps a ThreadLocal object to its value. + typedef std::map > + ThreadLocalValues; + // Stores all ThreadIdToThreadLocals having values in a thread, indexed by + // thread's ID. + typedef std::map ThreadIdToThreadLocals; + + // Holds the thread id and thread handle that we pass from + // StartWatcherThreadFor to WatcherThreadFunc. + typedef std::pair ThreadIdAndHandle; + + static void StartWatcherThreadFor(DWORD thread_id) { + // The returned handle will be kept in thread_map and closed by + // watcher_thread in WatcherThreadFunc. + HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, + FALSE, + thread_id); + GTEST_CHECK_(thread != nullptr); + // We need to pass a valid thread ID pointer into CreateThread for it + // to work correctly under Win98. + DWORD watcher_thread_id; + HANDLE watcher_thread = ::CreateThread( + nullptr, // Default security. + 0, // Default stack size + &ThreadLocalRegistryImpl::WatcherThreadFunc, + reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), + CREATE_SUSPENDED, &watcher_thread_id); + GTEST_CHECK_(watcher_thread != nullptr); + // Give the watcher thread the same priority as ours to avoid being + // blocked by it. + ::SetThreadPriority(watcher_thread, + ::GetThreadPriority(::GetCurrentThread())); + ::ResumeThread(watcher_thread); + ::CloseHandle(watcher_thread); + } + + // Monitors exit from a given thread and notifies those + // ThreadIdToThreadLocals about thread termination. + static DWORD WINAPI WatcherThreadFunc(LPVOID param) { + const ThreadIdAndHandle* tah = + reinterpret_cast(param); + GTEST_CHECK_( + ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); + OnThreadExit(tah->first); + ::CloseHandle(tah->second); + delete tah; + return 0; + } + + // Returns map of thread local instances. + static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { + mutex_.AssertHeld(); +#ifdef _MSC_VER + MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER + static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); + return map; + } + + // Protects access to GetThreadLocalsMapLocked() and its return value. + static Mutex mutex_; + // Protects access to GetThreadMapLocked() and its return value. + static Mutex thread_map_mutex_; +}; + +Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); +Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); + +ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + return ThreadLocalRegistryImpl::GetValueOnCurrentThread( + thread_local_instance); +} + +void ThreadLocalRegistry::OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); +} + +#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS #if GTEST_USES_POSIX_RE @@ -149,7 +715,7 @@ RE::~RE() { free(const_cast(pattern_)); } -// Returns true iff regular expression re matches the entire str. +// Returns true if and only if regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; @@ -157,8 +723,8 @@ bool RE::FullMatch(const char* str, const RE& re) { return regexec(&re.full_regex_, str, 1, &match, 0) == 0; } -// Returns true iff regular expression re matches a substring of str -// (including str itself). +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; @@ -198,14 +764,14 @@ void RE::Init(const char* regex) { #elif GTEST_USES_SIMPLE_RE -// Returns true iff ch appears anywhere in str (excluding the +// Returns true if and only if ch appears anywhere in str (excluding the // terminating '\0' character). bool IsInSet(char ch, const char* str) { - return ch != '\0' && strchr(str, ch) != NULL; + return ch != '\0' && strchr(str, ch) != nullptr; } -// Returns true iff ch belongs to the given classification. Unlike -// similar functions in , these aren't affected by the +// Returns true if and only if ch belongs to the given classification. +// Unlike similar functions in , these aren't affected by the // current locale. bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsAsciiPunct(char ch) { @@ -218,13 +784,13 @@ bool IsAsciiWordChar(char ch) { ('0' <= ch && ch <= '9') || ch == '_'; } -// Returns true iff "\\c" is a supported escape sequence. +// Returns true if and only if "\\c" is a supported escape sequence. bool IsValidEscape(char c) { return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); } -// Returns true iff the given atom (specified by escaped and pattern) -// matches ch. The result is undefined if the atom is invalid. +// Returns true if and only if the given atom (specified by escaped and +// pattern) matches ch. The result is undefined if the atom is invalid. bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { @@ -247,7 +813,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { } // Helper function used by ValidateRegex() to format error messages. -std::string FormatRegexSyntaxError(const char* regex, int index) { +static std::string FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } @@ -255,17 +821,14 @@ std::string FormatRegexSyntaxError(const char* regex, int index) { // Generates non-fatal failures and returns false if regex is invalid; // otherwise returns true. bool ValidateRegex(const char* regex) { - if (regex == NULL) { - // TODO(wan@google.com): fix the source file location in the - // assertion failures to match where the regex is used in user - // code. + if (regex == nullptr) { ADD_FAILURE() << "NULL is not a valid simple regular expression."; return false; } bool is_valid = true; - // True iff ?, *, or + can follow the previous atom. + // True if and only if ?, *, or + can follow the previous atom. bool prev_repeatable = false; for (int i = 0; regex[i]; i++) { if (regex[i] == '\\') { // An escape sequence @@ -341,8 +904,8 @@ bool MatchRepetitionAndRegexAtHead( return false; } -// Returns true iff regex matches a prefix of str. regex must be a -// valid simple regular expression and not start with "^", or the +// Returns true if and only if regex matches a prefix of str. regex must +// be a valid simple regular expression and not start with "^", or the // result is undefined. bool MatchRegexAtHead(const char* regex, const char* str) { if (*regex == '\0') // An empty regex matches a prefix of anything. @@ -372,8 +935,8 @@ bool MatchRegexAtHead(const char* regex, const char* str) { } } -// Returns true iff regex matches any substring of str. regex must be -// a valid simple regular expression, or the result is undefined. +// Returns true if and only if regex matches any substring of str. regex must +// be a valid simple regular expression, or the result is undefined. // // The algorithm is recursive, but the recursion depth doesn't exceed // the regex length, so we won't need to worry about running out of @@ -381,8 +944,7 @@ bool MatchRegexAtHead(const char* regex, const char* str) { // exponential with respect to the regex length + the string length, // but usually it's must faster (often close to linear). bool MatchRegexAnywhere(const char* regex, const char* str) { - if (regex == NULL || str == NULL) - return false; + if (regex == nullptr || str == nullptr) return false; if (*regex == '^') return MatchRegexAtHead(regex + 1, str); @@ -402,21 +964,21 @@ RE::~RE() { free(const_cast(full_pattern_)); } -// Returns true iff regular expression re matches the entire str. +// Returns true if and only if regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); } -// Returns true iff regular expression re matches a substring of str -// (including str itself). +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); } // Initializes an RE from its string representation. void RE::Init(const char* regex) { - pattern_ = full_pattern_ = NULL; - if (regex != NULL) { + pattern_ = full_pattern_ = nullptr; + if (regex != nullptr) { pattern_ = posix::StrDup(regex); } @@ -454,7 +1016,7 @@ const char kUnknownFile[] = "unknown file"; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); + const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) { return file_name + ":"; @@ -473,7 +1035,7 @@ GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { // to the file location it produces, unlike FormatFileLocation(). GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); + const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) return file_name; @@ -481,7 +1043,6 @@ GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( return file_name + ":" + StreamableToString(line); } - GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { const char* const marker = @@ -500,12 +1061,10 @@ GTestLog::~GTestLog() { posix::Abort(); } } + // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4996) -#endif // _MSC_VER +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() #if GTEST_HAS_STREAM_REDIRECTION @@ -543,20 +1102,22 @@ class CapturedStream { // code as part of a regular standalone executable, which doesn't // run in a Dalvik process (e.g. when running it through 'adb shell'). // - // The location /sdcard is directly accessible from native code - // and is the only location (unofficially) supported by the Android - // team. It's generally a symlink to the real SD Card mount point - // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or - // other OEM-customized locations. Never rely on these, and always - // use /sdcard. - char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; + // The location /data/local/tmp is directly accessible from native code. + // '/sdcard' and other variants cannot be relied on, as they are not + // guaranteed to be mounted, or may have a delay in mounting. + char name_template[] = "/data/local/tmp/gtest_captured_stream.XXXXXX"; # else char name_template[] = "/tmp/captured_stream.XXXXXX"; # endif // GTEST_OS_LINUX_ANDROID const int captured_fd = mkstemp(name_template); + if (captured_fd == -1) { + GTEST_LOG_(WARNING) + << "Failed to create tmp file " << name_template + << " for test; does the test have access to the /tmp directory?"; + } filename_ = name_template; # endif // GTEST_OS_WINDOWS - fflush(NULL); + fflush(nullptr); dup2(captured_fd, fd_); close(captured_fd); } @@ -568,25 +1129,23 @@ class CapturedStream { std::string GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. - fflush(NULL); + fflush(nullptr); dup2(uncaptured_fd_, fd_); close(uncaptured_fd_); uncaptured_fd_ = -1; } FILE* const file = posix::FOpen(filename_.c_str(), "r"); + if (file == nullptr) { + GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_ + << " for capturing stream."; + } const std::string content = ReadEntireFile(file); posix::FClose(file); return content; } private: - // Reads the entire content of a file as an std::string. - static std::string ReadEntireFile(FILE* file); - - // Returns the size (in bytes) of a file. - static size_t GetFileSize(FILE* file); - const int fd_; // A stream to capture. int uncaptured_fd_; // Name of the temporary file holding the stderr output. @@ -595,45 +1154,15 @@ class CapturedStream { GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; -// Returns the size (in bytes) of a file. -size_t CapturedStream::GetFileSize(FILE* file) { - fseek(file, 0, SEEK_END); - return static_cast(ftell(file)); -} +GTEST_DISABLE_MSC_DEPRECATED_POP_() -// Reads the entire content of a file as a string. -std::string CapturedStream::ReadEntireFile(FILE* file) { - const size_t file_size = GetFileSize(file); - char* const buffer = new char[file_size]; - - size_t bytes_last_read = 0; // # of bytes read in the last fread() - size_t bytes_read = 0; // # of bytes read so far - - fseek(file, 0, SEEK_SET); - - // Keeps reading the file until we cannot read further or the - // pre-determined file size is reached. - do { - bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); - bytes_read += bytes_last_read; - } while (bytes_last_read > 0 && bytes_read < file_size); - - const std::string content(buffer, bytes_read); - delete[] buffer; - - return content; -} - -# ifdef _MSC_VER -# pragma warning(pop) -# endif // _MSC_VER - -static CapturedStream* g_captured_stderr = NULL; -static CapturedStream* g_captured_stdout = NULL; +static CapturedStream* g_captured_stderr = nullptr; +static CapturedStream* g_captured_stdout = nullptr; // Starts capturing an output stream (stdout/stderr). -void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { - if (*stream != NULL) { +static void CaptureStream(int fd, const char* stream_name, + CapturedStream** stream) { + if (*stream != nullptr) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; } @@ -641,11 +1170,11 @@ void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { } // Stops capturing the output stream and returns the captured string. -std::string GetCapturedStream(CapturedStream** captured_stream) { +static std::string GetCapturedStream(CapturedStream** captured_stream) { const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; - *captured_stream = NULL; + *captured_stream = nullptr; return content; } @@ -672,25 +1201,61 @@ std::string GetCapturedStderr() { #endif // GTEST_HAS_STREAM_REDIRECTION -#if GTEST_HAS_DEATH_TEST -// A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; -static const ::std::vector* g_injected_test_argvs = - NULL; // Owned. -void SetInjectableArgvs(const ::std::vector* argvs) { - if (g_injected_test_argvs != argvs) - delete g_injected_test_argvs; - g_injected_test_argvs = argvs; + +size_t GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); } -const ::std::vector& GetInjectableArgvs() { - if (g_injected_test_argvs != NULL) { +std::string ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const std::string content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +#if GTEST_HAS_DEATH_TEST +static const std::vector* g_injected_test_argvs = + nullptr; // Owned. + +std::vector GetInjectableArgvs() { + if (g_injected_test_argvs != nullptr) { return *g_injected_test_argvs; } - return g_argvs; + return GetArgvs(); +} + +void SetInjectableArgvs(const std::vector* new_argvs) { + if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs; + g_injected_test_argvs = new_argvs; +} + +void SetInjectableArgvs(const std::vector& new_argvs) { + SetInjectableArgvs( + new std::vector(new_argvs.begin(), new_argvs.end())); +} + +void ClearInjectableArgvs() { + delete g_injected_test_argvs; + g_injected_test_argvs = nullptr; } #endif // GTEST_HAS_DEATH_TEST @@ -723,7 +1288,7 @@ static std::string FlagToEnvVar(const char* flag) { // unchanged and returns false. bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Parses the environment variable as a decimal integer. - char* end = NULL; + char* end = nullptr; const long long_value = strtol(str, &end, 10); // NOLINT // Has strtol() consumed all characters in the string? @@ -762,21 +1327,28 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Reads and returns the Boolean environment variable corresponding to // the given flag; if it's not set, returns default_value. // -// The value is considered true iff it's not "0". +// The value is considered true if and only if it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { +#if defined(GTEST_GET_BOOL_FROM_ENV_) + return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); - return string_value == NULL ? - default_value : strcmp(string_value, "0") != 0; + return string_value == nullptr ? default_value + : strcmp(string_value, "0") != 0; +#endif // defined(GTEST_GET_BOOL_FROM_ENV_) } // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { +#if defined(GTEST_GET_INT32_FROM_ENV_) + return GTEST_GET_INT32_FROM_ENV_(flag, default_value); +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); - if (string_value == NULL) { + if (string_value == nullptr) { // The environment variable is not set. return default_value; } @@ -791,14 +1363,36 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { } return result; +#endif // defined(GTEST_GET_INT32_FROM_ENV_) +} + +// As a special case for the 'output' flag, if GTEST_OUTPUT is not +// set, we look for XML_OUTPUT_FILE, which is set by the Bazel build +// system. The value of XML_OUTPUT_FILE is a filename without the +// "xml:" prefix of GTEST_OUTPUT. +// Note that this is meant to be called at the call site so it does +// not check that the flag is 'output' +// In essence this checks an env variable called XML_OUTPUT_FILE +// and if it is set we prepend "xml:" to its value, if it not set we return "" +std::string OutputFlagAlsoCheckEnvVar(){ + std::string default_value_for_output_flag = ""; + const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); + if (nullptr != xml_output_file_env) { + default_value_for_output_flag = std::string("xml:") + xml_output_file_env; + } + return default_value_for_output_flag; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { +#if defined(GTEST_GET_STRING_FROM_ENV_) + return GTEST_GET_STRING_FROM_ENV_(flag, default_value); +#else const std::string env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); - return value == NULL ? default_value : value; + return value == nullptr ? default_value : value; +#endif // defined(GTEST_GET_STRING_FROM_ENV_) } } // namespace internal diff --git a/test/gtest/src/gtest-printers.cc b/test/gtest/src/gtest-printers.cc index 75fa408100..3337be312e 100644 --- a/test/gtest/src/gtest-printers.cc +++ b/test/gtest/src/gtest-printers.cc @@ -26,10 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -43,11 +42,13 @@ // defines Foo. #include "gtest/gtest-printers.h" -#include #include +#include +#include #include // NOLINT #include #include "gtest/internal/gtest-port.h" +#include "src/gtest-internal-inl.h" namespace testing { @@ -56,6 +57,10 @@ namespace { using ::std::ostream; // Prints a segment of bytes in the given object. +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; @@ -85,7 +90,6 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. - // TODO(wan): let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { @@ -119,7 +123,7 @@ namespace internal { // Depending on the value of a char (or wchar_t), we print it in one // of three formats: // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), -// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a hexadecimal escape sequence (e.g. '\x7F'), or // - as a special escape sequence (e.g. '\r', '\n'). enum CharFormat { kAsIs, @@ -140,7 +144,8 @@ inline bool IsPrintableAscii(wchar_t c) { // which is the type of c. template static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { - switch (static_cast(c)) { + wchar_t w_c = static_cast(c); + switch (w_c) { case L'\0': *os << "\\0"; break; @@ -172,11 +177,14 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { *os << "\\v"; break; default: - if (IsPrintableAscii(c)) { + if (IsPrintableAscii(w_c)) { *os << static_cast(c); return kAsIs; } else { - *os << "\\x" + String::FormatHexInt(static_cast(c)); + ostream::fmtflags flags = os->flags(); + *os << "\\x" << std::hex << std::uppercase + << static_cast(static_cast(c)); + os->flags(flags); return kHexEscape; } } @@ -223,13 +231,13 @@ void PrintCharAndCodeTo(Char c, ostream* os) { return; *os << " (" << static_cast(c); - // For more convenience, we print c's code again in hexidecimal, + // For more convenience, we print c's code again in hexadecimal, // unless c was already printed in the form '\x##' or the code is in // [1, 9]. if (format == kHexEscape || (1 <= c && c <= 9)) { // Do nothing. } else { - *os << ", 0x" << String::FormatHexInt(static_cast(c)); + *os << ", 0x" << String::FormatHexInt(static_cast(c)); } *os << ")"; } @@ -252,11 +260,16 @@ void PrintTo(wchar_t wc, ostream* os) { // The array starts at begin, the length is len, it may include '\0' characters // and may not be NUL-terminated. template -static void PrintCharsAsStringTo( +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +static CharFormat PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; + CharFormat print_format = kAsIs; for (size_t index = 0; index < len; ++index) { const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(cur)) { @@ -266,13 +279,22 @@ static void PrintCharsAsStringTo( *os << "\" " << kQuoteBegin; } is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; + // Remember if any characters required hex escaping. + if (is_previous_hex) { + print_format = kHexEscape; + } } *os << "\""; + return print_format; } // Prints a (const) char/wchar_t array of 'len' elements, starting at address // 'begin'. CharType must be either char or wchar_t. template +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code @@ -308,7 +330,7 @@ void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { // Prints the given C string to the ostream. void PrintTo(const char* s, ostream* os) { - if (s == NULL) { + if (s == nullptr) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; @@ -325,7 +347,7 @@ void PrintTo(const char* s, ostream* os) { #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Prints the given wide C string to the ostream. void PrintTo(const wchar_t* s, ostream* os) { - if (s == NULL) { + if (s == nullptr) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; @@ -334,23 +356,80 @@ void PrintTo(const wchar_t* s, ostream* os) { } #endif // wchar_t is native -// Prints a ::string object. -#if GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); +namespace { + +bool ContainsUnprintableControlCodes(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length; i++) { + unsigned char ch = *s++; + if (std::iscntrl(ch)) { + switch (ch) { + case '\t': + case '\n': + case '\r': + break; + default: + return true; + } + } + } + return false; } -#endif // GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::std::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); +bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; } + +bool IsValidUTF8(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length;) { + unsigned char lead = s[i++]; + + if (lead <= 0x7f) { + continue; // single-byte character (ASCII) 0..7F + } + if (lead < 0xc2) { + return false; // trail byte or non-shortest form + } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) { + ++i; // 2-byte character + } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + // check for non-shortest form and surrogate + (lead != 0xe0 || s[i] >= 0xa0) && + (lead != 0xed || s[i] < 0xa0)) { + i += 2; // 3-byte character + } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + IsUTF8TrailByte(s[i + 2]) && + // check for non-shortest form + (lead != 0xf0 || s[i] >= 0x90) && + (lead != 0xf4 || s[i] < 0x90)) { + i += 3; // 4-byte character + } else { + return false; + } + } + return true; } -// Prints a ::wstring object. -#if GTEST_HAS_GLOBAL_WSTRING -void PrintWideStringTo(const ::wstring& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); +void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { + if (!ContainsUnprintableControlCodes(str, length) && + IsValidUTF8(str, length)) { + *os << "\n As Text: \"" << str << "\""; + } +} + +} // anonymous namespace + +void PrintStringTo(const ::std::string& s, ostream* os) { + if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { + if (GTEST_FLAG(print_utf8)) { + ConditionalPrintAsText(s.data(), s.size(), os); + } + } } -#endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING void PrintWideStringTo(const ::std::wstring& s, ostream* os) { diff --git a/test/gtest/src/gtest-test-part.cc b/test/gtest/src/gtest-test-part.cc index c60eef3ab3..178317a6bc 100644 --- a/test/gtest/src/gtest-test-part.cc +++ b/test/gtest/src/gtest-test-part.cc @@ -26,21 +26,12 @@ // 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. + // -// Author: mheule@google.com (Markus Heule) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest-test-part.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { @@ -50,18 +41,21 @@ using internal::GetUnitTestImpl; // in it. std::string TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); - return stack_trace == NULL ? message : - std::string(message, stack_trace); + return stack_trace == nullptr ? message : std::string(message, stack_trace); } // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os - << result.file_name() << ":" << result.line_number() << ": " - << (result.type() == TestPartResult::kSuccess ? "Success" : - result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; + return os << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess + ? "Success" + : result.type() == TestPartResult::kSkip + ? "Skipped" + : result.type() == TestPartResult::kFatalFailure + ? "Fatal failure" + : "Non-fatal failure") + << ":\n" + << result.message() << std::endl; } // Appends a TestPartResult to the array. @@ -76,7 +70,7 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { internal::posix::Abort(); } - return array_[index]; + return array_[static_cast(index)]; } // Returns the number of TestPartResult objects in the array. diff --git a/test/gtest/src/gtest-typed-test.cc b/test/gtest/src/gtest-typed-test.cc index f0079f407c..8677caf732 100644 --- a/test/gtest/src/gtest-typed-test.cc +++ b/test/gtest/src/gtest-typed-test.cc @@ -26,10 +26,10 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + #include "gtest/gtest-typed-test.h" + #include "gtest/gtest.h" namespace testing { @@ -45,33 +45,41 @@ static const char* SkipSpaces(const char* str) { return str; } +static std::vector SplitIntoTestNames(const char* src) { + std::vector name_vec; + src = SkipSpaces(src); + for (; src != nullptr; src = SkipComma(src)) { + name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); + } + return name_vec; +} + // Verifies that registered_tests match the test names in -// defined_test_names_; returns registered_tests if successful, or +// registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. -const char* TypedTestCasePState::VerifyRegisteredTestNames( +const char* TypedTestSuitePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { - typedef ::std::set::const_iterator DefinedTestIter; + typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; - // Skip initial whitespace in registered_tests since some - // preprocessors prefix stringizied literals with whitespace. - registered_tests = SkipSpaces(registered_tests); + std::vector name_vec = SplitIntoTestNames(registered_tests); Message errors; - ::std::set tests; - for (const char* names = registered_tests; names != NULL; - names = SkipComma(names)) { - const std::string name = GetPrefixUntilComma(names); + + std::set tests; + for (std::vector::const_iterator name_it = name_vec.begin(); + name_it != name_vec.end(); ++name_it) { + const std::string& name = *name_it; if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; } bool found = false; - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); ++it) { - if (name == *it) { + if (name == it->first) { found = true; break; } @@ -81,15 +89,15 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( tests.insert(name); } else { errors << "No test named " << name - << " can be found in this test case.\n"; + << " can be found in this test suite.\n"; } } - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); ++it) { - if (tests.count(*it) == 0) { - errors << "You forgot to list test " << *it << ".\n"; + if (tests.count(it->first) == 0) { + errors << "You forgot to list test " << it->first << ".\n"; } } diff --git a/test/gtest/src/gtest.cc b/test/gtest/src/gtest.cc index 7ee9368320..1dff1a6afb 100644 --- a/test/gtest/src/gtest.cc +++ b/test/gtest/src/gtest.cc @@ -26,14 +26,17 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest.h" +#include "gtest/internal/custom/gtest.h" #include "gtest/gtest-spi.h" + +#ifndef _WIN32 #pragma GCC system_header +#endif #include #include @@ -47,14 +50,14 @@ #include #include #include +#include +#include #include // NOLINT #include #include #if GTEST_OS_LINUX -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT @@ -67,10 +70,6 @@ # include // NOLINT # include -#elif GTEST_OS_SYMBIAN -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT - #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT @@ -81,9 +80,15 @@ #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT +# undef min #elif GTEST_OS_WINDOWS // We are on Windows proper. +# include // NOLINT +# undef min + +# include // NOLINT +# include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT @@ -91,24 +96,13 @@ # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -// TODO(kenton@google.com): There are other ways to get the time on -// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW -// supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # endif // GTEST_OS_WINDOWS_MINGW -// cpplint thinks that the header is already included, so we want to -// silence it. -# include // NOLINT - #else // Assume other platforms have gettimeofday(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to @@ -125,21 +119,29 @@ #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT +# include // NOLINT +# include // NOLINT #endif -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS +#include +#endif +#endif + +#if GTEST_HAS_ABSL +#include "absl/debugging/failure_signal_handler.h" +#include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" +#include "absl/strings/str_cat.h" +#endif // GTEST_HAS_ABSL + namespace testing { using internal::CountIf; @@ -149,20 +151,22 @@ using internal::Shuffle; // Constants. -// A test whose test case name or test name matches this filter is +// A test whose test suite name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; -// A test case whose name matches this filter is considered a death -// test case and will be run before test cases whose name doesn't +// A test suite whose name matches this filter is considered a death +// test suite and will be run before test suites whose name doesn't // match this filter. -static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; +static const char kDeathTestSuiteFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; -// The default output file for XML output. -static const char kDefaultOutputFile[] = "test_detail.xml"; +// The default output format. +static const char kDefaultOutputFormat[] = "xml"; +// The default output file. +static const char kDefaultOutputFile[] = "test_detail"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; @@ -177,13 +181,35 @@ namespace internal { // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. bool g_help_flag = false; +// Utilty function to Open File for Writing +static FILE* OpenFileForWriting(const std::string& output_file) { + FILE* fileout = nullptr; + FilePath output_file_path(output_file); + FilePath output_dir(output_file_path.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + fileout = posix::FOpen(output_file.c_str(), "w"); + } + if (fileout == nullptr) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\""; + } + return fileout; +} + } // namespace internal +// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY +// environment variable. static const char* GetDefaultFilter() { + const char* const testbridge_test_only = + internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY"); + if (testbridge_test_only != nullptr) { + return testbridge_test_only; + } return kUniversalFilter; } @@ -193,15 +219,14 @@ GTEST_DEFINE_bool_( "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( - break_on_failure, - internal::BoolFromGTestEnv("break_on_failure", false), - "True iff a failed assertion should be a debugger break-point."); + break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), + "True if and only if a failed assertion should be a debugger " + "break-point."); -GTEST_DEFINE_bool_( - catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", true), - "True iff " GTEST_NAME_ - " should catch exceptions and treat them as test failures."); +GTEST_DEFINE_bool_(catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True if and only if " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, @@ -220,26 +245,41 @@ GTEST_DEFINE_string_( "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); +GTEST_DEFINE_bool_( + install_failure_signal_handler, + internal::BoolFromGTestEnv("install_failure_signal_handler", false), + "If true and supported on the current platform, " GTEST_NAME_ " should " + "install a signal handler that dumps debugging information when fatal " + "signals are raised."); + GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); +// The net priority order after flag processing is thus: +// --gtest_output command line flag +// GTEST_OUTPUT environment variable +// XML_OUTPUT_FILE environment variable +// '' GTEST_DEFINE_string_( output, - internal::StringFromGTestEnv("output", ""), - "A format (currently must be \"xml\"), optionally followed " - "by a colon and an output file name or directory. A directory " - "is indicated by a trailing pathname separator. " + internal::StringFromGTestEnv("output", + internal::OutputFlagAlsoCheckEnvVar().c_str()), + "A format (defaults to \"xml\" but can be specified to be \"json\"), " + "optionally followed by a colon and an output file name or directory. " + "A directory is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " "executable's name and, if necessary, made unique by adding " "digits."); -GTEST_DEFINE_bool_( - print_time, - internal::BoolFromGTestEnv("print_time", true), - "True iff " GTEST_NAME_ - " should display elapsed time in text output."); +GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true), + "True if and only if " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_bool_(print_utf8, internal::BoolFromGTestEnv("print_utf8", true), + "True if and only if " GTEST_NAME_ + " prints UTF8 characters as text."); GTEST_DEFINE_int32_( random_seed, @@ -253,16 +293,14 @@ GTEST_DEFINE_int32_( "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); -GTEST_DEFINE_bool_( - show_internal_stack_frames, false, - "True iff " GTEST_NAME_ " should include internal stack frames when " - "printing test failure stack traces."); +GTEST_DEFINE_bool_(show_internal_stack_frames, false, + "True if and only if " GTEST_NAME_ + " should include internal stack frames when " + "printing test failure stack traces."); -GTEST_DEFINE_bool_( - shuffle, - internal::BoolFromGTestEnv("shuffle", false), - "True iff " GTEST_NAME_ - " should randomize tests' order on every run."); +GTEST_DEFINE_bool_(shuffle, internal::BoolFromGTestEnv("shuffle", false), + "True if and only if " GTEST_NAME_ + " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, @@ -282,7 +320,14 @@ GTEST_DEFINE_bool_( internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " - "otherwise."); + "otherwise. For use with an external test framework."); + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DEFINE_string_( + flagfile, + internal::StringFromGTestEnv("flagfile", ""), + "This flag specifies the flagfile to read command-line flags from."); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ namespace internal { @@ -291,7 +336,8 @@ namespace internal { // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). - state_ = (1103515245U*state_ + 12345U) % kMaxRange; + // Use wider types than necessary to prevent unsigned overflow diagnostics. + state_ = static_cast(1103515245ULL*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; @@ -305,22 +351,16 @@ UInt32 Random::Generate(UInt32 range) { return state_ % range; } -// GTestIsInitialized() returns true iff the user has initialized +// GTestIsInitialized() returns true if and only if the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). -// -// A user must call testing::InitGoogleTest() to initialize Google -// Test. g_init_gtest_count is set to the number of times -// InitGoogleTest() has been called. We don't protect this variable -// under a mutex as it is only accessed in the main thread. -GTEST_API_ int g_init_gtest_count = 0; -static bool GTestIsInitialized() { return g_init_gtest_count != 0; } - -// Iterates over a vector of TestCases, keeping a running sum of the +static bool GTestIsInitialized() { return GetArgvs().size() > 0; } + +// Iterates over a vector of TestSuites, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. -static int SumOverTestCaseList(const std::vector& case_list, - int (TestCase::*method)() const) { +static int SumOverTestSuiteList(const std::vector& case_list, + int (TestSuite::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); @@ -328,20 +368,20 @@ static int SumOverTestCaseList(const std::vector& case_list, return sum; } -// Returns true iff the test case passed. -static bool TestCasePassed(const TestCase* test_case) { - return test_case->should_run() && test_case->Passed(); +// Returns true if and only if the test suite passed. +static bool TestSuitePassed(const TestSuite* test_suite) { + return test_suite->should_run() && test_suite->Passed(); } -// Returns true iff the test case failed. -static bool TestCaseFailed(const TestCase* test_case) { - return test_case->should_run() && test_case->Failed(); +// Returns true if and only if the test suite failed. +static bool TestSuiteFailed(const TestSuite* test_suite) { + return test_suite->should_run() && test_suite->Failed(); } -// Returns true iff test_case contains at least one test that should -// run. -static bool ShouldRunTestCase(const TestCase* test_case) { - return test_case->should_run(); +// Returns true if and only if test_suite contains at least one test that +// should run. +static bool ShouldRunTestSuite(const TestSuite* test_suite) { + return test_suite->should_run(); } // AssertHelper constructor. @@ -367,21 +407,29 @@ void AssertHelper::operator=(const Message& message) const { ); // NOLINT } -// Mutex for linked pointers. -GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); +// A copy of all command line arguments. Set by InitGoogleTest(). +static ::std::vector g_argvs; -// Application pathname gotten in InitGoogleTest. -std::string g_executable_path; +::std::vector GetArgvs() { +#if defined(GTEST_CUSTOM_GET_ARGVS_) + // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or + // ::string. This code converts it to the appropriate type. + const auto& custom = GTEST_CUSTOM_GET_ARGVS_(); + return ::std::vector(custom.begin(), custom.end()); +#else // defined(GTEST_CUSTOM_GET_ARGVS_) + return g_argvs; +#endif // defined(GTEST_CUSTOM_GET_ARGVS_) +} // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; -#if GTEST_OS_WINDOWS - result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#if GTEST_OS_WINDOWS || GTEST_OS_OS2 + result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe")); #else - result.Set(FilePath(g_executable_path)); + result.Set(FilePath(GetArgvs()[0])); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); @@ -392,34 +440,32 @@ FilePath GetCurrentExecutableName() { // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return std::string(""); - const char* const colon = strchr(gtest_output_flag, ':'); - return (colon == NULL) ? - std::string(gtest_output_flag) : - std::string(gtest_output_flag, colon - gtest_output_flag); + return (colon == nullptr) + ? std::string(gtest_output_flag) + : std::string(gtest_output_flag, + static_cast(colon - gtest_output_flag)); } // Returns the name of the requested output file, or the default if none // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) - return ""; + + std::string format = GetOutputFormat(); + if (format.empty()) + format = std::string(kDefaultOutputFormat); const char* const colon = strchr(gtest_output_flag, ':'); - if (colon == NULL) - return internal::FilePath::ConcatPaths( + if (colon == nullptr) + return internal::FilePath::MakeFileName( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).string(); + internal::FilePath(kDefaultOutputFile), 0, + format.c_str()).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) - // TODO(wan@google.com): on Windows \some\path is not an absolute - // path (as its meaning depends on the current drive), yet the - // following logic for turning it into an absolute path is wrong. - // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); @@ -433,8 +479,8 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() { return result.string(); } -// Returns true iff the wildcard pattern matches the string. The -// first ':' or '\0' character in pattern marks the end of it. +// Returns true if and only if the wildcard pattern matches the string. +// The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. @@ -467,7 +513,7 @@ bool UnitTestOptions::MatchesFilter( cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. - if (cur_pattern == NULL) { + if (cur_pattern == nullptr) { return false; } @@ -476,11 +522,11 @@ bool UnitTestOptions::MatchesFilter( } } -// Returns true iff the user-specified filter matches the test case -// name and the test name. -bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name) { - const std::string& full_name = test_case_name + "." + test_name.c_str(); +// Returns true if and only if the user-specified filter matches the test +// suite name and the test name. +bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name, + const std::string& test_name) { + const std::string& full_name = test_suite_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions @@ -488,7 +534,7 @@ bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, const char* const dash = strchr(p, '-'); std::string positive; std::string negative; - if (dash == NULL) { + if (dash == nullptr) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { @@ -607,12 +653,12 @@ extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. -AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, - TestPartResult::Type type, - const string& substr) { +static AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const std::string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); @@ -633,7 +679,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */, << r; } - if (strstr(r.message(), substr.c_str()) == NULL) { + if (strstr(r.message(), substr.c_str()) == nullptr) { return AssertionFailure() << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" @@ -646,13 +692,10 @@ AssertionResult HasOneFailure(const char* /* results_expr */, // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. -SingleFailureChecker:: SingleFailureChecker( - const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr) - : results_(results), - type_(type), - substr_(substr) {} +SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const std::string& substr) + : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given @@ -705,61 +748,66 @@ void UnitTestImpl::SetTestPartResultReporterForCurrentThread( per_thread_test_part_result_reporter_.set(reporter); } -// Gets the number of successful test cases. -int UnitTestImpl::successful_test_case_count() const { - return CountIf(test_cases_, TestCasePassed); +// Gets the number of successful test suites. +int UnitTestImpl::successful_test_suite_count() const { + return CountIf(test_suites_, TestSuitePassed); } -// Gets the number of failed test cases. -int UnitTestImpl::failed_test_case_count() const { - return CountIf(test_cases_, TestCaseFailed); +// Gets the number of failed test suites. +int UnitTestImpl::failed_test_suite_count() const { + return CountIf(test_suites_, TestSuiteFailed); } -// Gets the number of all test cases. -int UnitTestImpl::total_test_case_count() const { - return static_cast(test_cases_.size()); +// Gets the number of all test suites. +int UnitTestImpl::total_test_suite_count() const { + return static_cast(test_suites_.size()); } -// Gets the number of all test cases that contain at least one test +// Gets the number of all test suites that contain at least one test // that should run. -int UnitTestImpl::test_case_to_run_count() const { - return CountIf(test_cases_, ShouldRunTestCase); +int UnitTestImpl::test_suite_to_run_count() const { + return CountIf(test_suites_, ShouldRunTestSuite); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::successful_test_count); +} + +// Gets the number of skipped tests. +int UnitTestImpl::skipped_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::skipped_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::failed_test_count); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { - return SumOverTestCaseList(test_cases_, - &TestCase::reportable_disabled_test_count); + return SumOverTestSuiteList(test_suites_, + &TestSuite::reportable_disabled_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::disabled_test_count); } // Gets the number of tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::test_to_run_count); } // Returns the current OS stack trace as an std::string. @@ -773,8 +821,12 @@ int UnitTestImpl::test_to_run_count() const { // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { - (void)skip_count; - return ""; + return os_stack_trace_getter()->CurrentStackTrace( + static_cast(GTEST_FLAG(stack_trace_depth)), + skip_count + 1 + // Skips the user-specified number of frames plus this function + // itself. + ); // NOLINT } // Returns the current time in milliseconds. @@ -789,8 +841,6 @@ TimeInMillis GetTimeInMillis() { SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; - // TODO(kenton@google.com): Shouldn't this just use - // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; @@ -803,26 +853,16 @@ TimeInMillis GetTimeInMillis() { #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; -# ifdef _MSC_VER - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. - // TODO(kenton@google.com): Use GetTickCount()? Or use - // SystemTimeToFileTime() -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996. - _ftime64(&now); -# pragma warning(pop) // Restores the warning state. -# else - + GTEST_DISABLE_MSC_DEPRECATED_PUSH_() _ftime64(&now); - -# endif // _MSC_VER + GTEST_DISABLE_MSC_DEPRECATED_POP_() return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else # error "Don't know how to get the current time on your system." @@ -839,11 +879,10 @@ TimeInMillis GetTimeInMillis() { // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { - if (!ansi) return NULL; + if (!ansi) return nullptr; const int length = strlen(ansi); const int unicode_length = - MultiByteToWideChar(CP_ACP, 0, ansi, length, - NULL, 0); + MultiByteToWideChar(CP_ACP, 0, ansi, length, nullptr, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); @@ -856,33 +895,33 @@ LPCWSTR String::AnsiToUtf16(const char* ansi) { // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { - if (!utf16_str) return NULL; - const int ansi_length = - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - NULL, 0, NULL, NULL); + if (!utf16_str) return nullptr; + const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, nullptr, + 0, nullptr, nullptr); char* ansi = new char[ansi_length + 1]; - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - ansi, ansi_length, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, nullptr, + nullptr); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE -// Compares two C strings. Returns true iff they have the same content. +// Compares two C strings. Returns true if and only if they have the same +// content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { - if ( lhs == NULL ) return rhs == NULL; + if (lhs == nullptr) return rhs == nullptr; - if ( rhs == NULL ) return false; + if (rhs == nullptr) return false; return strcmp(lhs, rhs) == 0; } -#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +#if GTEST_HAS_STD_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. @@ -900,7 +939,24 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, } } -#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +#endif // GTEST_HAS_STD_WSTRING + +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} } // namespace internal @@ -933,15 +989,6 @@ Message& Message::operator <<(const ::std::wstring& wstr) { } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_GLOBAL_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_GLOBAL_WSTRING - // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { @@ -952,16 +999,21 @@ std::string Message::GetString() const { // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), - message_(other.message_.get() != NULL ? - new ::std::string(*other.message_) : - static_cast< ::std::string*>(NULL)) { + message_(other.message_.get() != nullptr + ? new ::std::string(*other.message_) + : static_cast< ::std::string*>(nullptr)) {} + +// Swaps two AssertionResults. +void AssertionResult::swap(AssertionResult& other) { + using std::swap; + swap(success_, other.success_); + swap(message_, other.message_); } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); - if (message_.get() != NULL) - negation << *message_; + if (message_.get() != nullptr) negation << *message_; return negation; } @@ -983,6 +1035,277 @@ AssertionResult AssertionFailure(const Message& message) { namespace internal { +namespace edit_distance { +std::vector CalculateOptimalEdits(const std::vector& left, + const std::vector& right) { + std::vector > costs( + left.size() + 1, std::vector(right.size() + 1)); + std::vector > best_move( + left.size() + 1, std::vector(right.size() + 1)); + + // Populate for empty right. + for (size_t l_i = 0; l_i < costs.size(); ++l_i) { + costs[l_i][0] = static_cast(l_i); + best_move[l_i][0] = kRemove; + } + // Populate for empty left. + for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { + costs[0][r_i] = static_cast(r_i); + best_move[0][r_i] = kAdd; + } + + for (size_t l_i = 0; l_i < left.size(); ++l_i) { + for (size_t r_i = 0; r_i < right.size(); ++r_i) { + if (left[l_i] == right[r_i]) { + // Found a match. Consume it. + costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; + best_move[l_i + 1][r_i + 1] = kMatch; + continue; + } + + const double add = costs[l_i + 1][r_i]; + const double remove = costs[l_i][r_i + 1]; + const double replace = costs[l_i][r_i]; + if (add < remove && add < replace) { + costs[l_i + 1][r_i + 1] = add + 1; + best_move[l_i + 1][r_i + 1] = kAdd; + } else if (remove < add && remove < replace) { + costs[l_i + 1][r_i + 1] = remove + 1; + best_move[l_i + 1][r_i + 1] = kRemove; + } else { + // We make replace a little more expensive than add/remove to lower + // their priority. + costs[l_i + 1][r_i + 1] = replace + 1.00001; + best_move[l_i + 1][r_i + 1] = kReplace; + } + } + } + + // Reconstruct the best path. We do it in reverse order. + std::vector best_path; + for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { + EditType move = best_move[l_i][r_i]; + best_path.push_back(move); + l_i -= move != kAdd; + r_i -= move != kRemove; + } + std::reverse(best_path.begin(), best_path.end()); + return best_path; +} + +namespace { + +// Helper class to convert string into ids with deduplication. +class InternalStrings { + public: + size_t GetId(const std::string& str) { + IdMap::iterator it = ids_.find(str); + if (it != ids_.end()) return it->second; + size_t id = ids_.size(); + return ids_[str] = id; + } + + private: + typedef std::map IdMap; + IdMap ids_; +}; + +} // namespace + +std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right) { + std::vector left_ids, right_ids; + { + InternalStrings intern_table; + for (size_t i = 0; i < left.size(); ++i) { + left_ids.push_back(intern_table.GetId(left[i])); + } + for (size_t i = 0; i < right.size(); ++i) { + right_ids.push_back(intern_table.GetId(right[i])); + } + } + return CalculateOptimalEdits(left_ids, right_ids); +} + +namespace { + +// Helper class that holds the state for one hunk and prints it out to the +// stream. +// It reorders adds/removes when possible to group all removes before all +// adds. It also adds the hunk header before printint into the stream. +class Hunk { + public: + Hunk(size_t left_start, size_t right_start) + : left_start_(left_start), + right_start_(right_start), + adds_(), + removes_(), + common_() {} + + void PushLine(char edit, const char* line) { + switch (edit) { + case ' ': + ++common_; + FlushEdits(); + hunk_.push_back(std::make_pair(' ', line)); + break; + case '-': + ++removes_; + hunk_removes_.push_back(std::make_pair('-', line)); + break; + case '+': + ++adds_; + hunk_adds_.push_back(std::make_pair('+', line)); + break; + } + } + + void PrintTo(std::ostream* os) { + PrintHeader(os); + FlushEdits(); + for (std::list >::const_iterator it = + hunk_.begin(); + it != hunk_.end(); ++it) { + *os << it->first << it->second << "\n"; + } + } + + bool has_edits() const { return adds_ || removes_; } + + private: + void FlushEdits() { + hunk_.splice(hunk_.end(), hunk_removes_); + hunk_.splice(hunk_.end(), hunk_adds_); + } + + // Print a unified diff header for one hunk. + // The format is + // "@@ -, +, @@" + // where the left/right parts are omitted if unnecessary. + void PrintHeader(std::ostream* ss) const { + *ss << "@@ "; + if (removes_) { + *ss << "-" << left_start_ << "," << (removes_ + common_); + } + if (removes_ && adds_) { + *ss << " "; + } + if (adds_) { + *ss << "+" << right_start_ << "," << (adds_ + common_); + } + *ss << " @@\n"; + } + + size_t left_start_, right_start_; + size_t adds_, removes_, common_; + std::list > hunk_, hunk_adds_, hunk_removes_; +}; + +} // namespace + +// Create a list of diff hunks in Unified diff format. +// Each hunk has a header generated by PrintHeader above plus a body with +// lines prefixed with ' ' for no change, '-' for deletion and '+' for +// addition. +// 'context' represents the desired unchanged prefix/suffix around the diff. +// If two hunks are close enough that their contexts overlap, then they are +// joined into one hunk. +std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context) { + const std::vector edits = CalculateOptimalEdits(left, right); + + size_t l_i = 0, r_i = 0, edit_i = 0; + std::stringstream ss; + while (edit_i < edits.size()) { + // Find first edit. + while (edit_i < edits.size() && edits[edit_i] == kMatch) { + ++l_i; + ++r_i; + ++edit_i; + } + + // Find the first line to include in the hunk. + const size_t prefix_context = std::min(l_i, context); + Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); + for (size_t i = prefix_context; i > 0; --i) { + hunk.PushLine(' ', left[l_i - i].c_str()); + } + + // Iterate the edits until we found enough suffix for the hunk or the input + // is over. + size_t n_suffix = 0; + for (; edit_i < edits.size(); ++edit_i) { + if (n_suffix >= context) { + // Continue only if the next hunk is very close. + auto it = edits.begin() + static_cast(edit_i); + while (it != edits.end() && *it == kMatch) ++it; + if (it == edits.end() || + static_cast(it - edits.begin()) - edit_i >= context) { + // There is no next edit or it is too far away. + break; + } + } + + EditType edit = edits[edit_i]; + // Reset count when a non match is found. + n_suffix = edit == kMatch ? n_suffix + 1 : 0; + + if (edit == kMatch || edit == kRemove || edit == kReplace) { + hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); + } + if (edit == kAdd || edit == kReplace) { + hunk.PushLine('+', right[r_i].c_str()); + } + + // Advance indices, depending on edit type. + l_i += edit != kAdd; + r_i += edit != kRemove; + } + + if (!hunk.has_edits()) { + // We are done. We don't want this hunk. + break; + } + + hunk.PrintTo(&ss); + } + return ss.str(); +} + +} // namespace edit_distance + +namespace { + +// The string representation of the values received in EqFailure() are already +// escaped. Split them on escaped '\n' boundaries. Leave all other escaped +// characters the same. +std::vector SplitEscapedString(const std::string& str) { + std::vector lines; + size_t start = 0, end = str.size(); + if (end > 2 && str[0] == '"' && str[end - 1] == '"') { + ++start; + --end; + } + bool escaped = false; + for (size_t i = start; i + 1 < end; ++i) { + if (escaped) { + escaped = false; + if (str[i] == 'n') { + lines.push_back(str.substr(start, i - start - 1)); + start = i + 1; + } + } else { + escaped = str[i] == '\\'; + } + } + lines.push_back(str.substr(start, end - start)); + return lines; +} + +} // namespace + // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // @@ -990,31 +1313,43 @@ namespace internal { // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" +// lhs_expression: "foo" +// rhs_expression: "bar" +// lhs_value: "5" +// rhs_value: "6" // -// The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// The ignoring_case parameter is true if and only if the assertion is a +// *_STRCASEEQ*. When it's true, the string "Ignoring case" will // be inserted into the message. -AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const std::string& expected_value, - const std::string& actual_value, +AssertionResult EqFailure(const char* lhs_expression, + const char* rhs_expression, + const std::string& lhs_value, + const std::string& rhs_value, bool ignoring_case) { Message msg; - msg << "Value of: " << actual_expression; - if (actual_value != actual_expression) { - msg << "\n Actual: " << actual_value; + msg << "Expected equality of these values:"; + msg << "\n " << lhs_expression; + if (lhs_value != lhs_expression) { + msg << "\n Which is: " << lhs_value; + } + msg << "\n " << rhs_expression; + if (rhs_value != rhs_expression) { + msg << "\n Which is: " << rhs_value; } - msg << "\nExpected: " << expected_expression; if (ignoring_case) { - msg << " (ignoring case)"; + msg << "\nIgnoring case"; } - if (expected_value != expected_expression) { - msg << "\nWhich is: " << expected_value; + + if (!lhs_value.empty() && !rhs_value.empty()) { + const std::vector lhs_lines = + SplitEscapedString(lhs_value); + const std::vector rhs_lines = + SplitEscapedString(rhs_value); + if (lhs_lines.size() > 1 || rhs_lines.size() > 1) { + msg << "\nWith diff:\n" + << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines); + } } return AssertionFailure() << msg; @@ -1046,8 +1381,6 @@ AssertionResult DoubleNearPredFormat(const char* expr1, const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); - // TODO(wan): do not print the value of an expression if it's - // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" @@ -1112,18 +1445,18 @@ namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - if (expected == actual) { +AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs) { + if (lhs == rhs) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), + return EqFailure(lhs_expression, + rhs_expression, + FormatForComparisonFailureMessage(lhs, rhs), + FormatForComparisonFailureMessage(rhs, lhs), false); } @@ -1162,34 +1495,34 @@ GTEST_IMPL_CMP_HELPER_(GT, > ) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CStringEquals(expected, actual)) { +AssertionResult CmpHelperSTREQ(const char* lhs_expression, + const char* rhs_expression, + const char* lhs, + const char* rhs) { + if (String::CStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. -AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CaseInsensitiveCStringEquals(expected, actual)) { +AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression, + const char* rhs_expression, + const char* lhs, + const char* rhs) { + if (String::CaseInsensitiveCStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), true); } @@ -1228,22 +1561,20 @@ namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). -// This group of overloaded functions return true iff needle is a -// substring of haystack. NULL is considered a substring of itself -// only. +// This group of overloaded functions return true if and only if needle +// is a substring of haystack. NULL is considered a substring of +// itself only. bool IsSubstringPred(const char* needle, const char* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; + if (needle == nullptr || haystack == nullptr) return needle == haystack; - return strstr(haystack, needle) != NULL; + return strstr(haystack, needle) != nullptr; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; + if (needle == nullptr || haystack == nullptr) return needle == haystack; - return wcsstr(haystack, needle) != NULL; + return wcsstr(haystack, needle) != nullptr; } // StringType here can be either ::std::string or ::std::wstring. @@ -1341,7 +1672,7 @@ namespace { AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT -# if GTEST_OS_WINDOWS_MOBILE +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; @@ -1357,12 +1688,12 @@ AssertionResult HRESULTFailureHelper(const char* expr, // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, - 0, // no source, we're asking system - hr, // the error - 0, // no line width restrictions + 0, // no source, we're asking system + static_cast(hr), // the error + 0, // no line width restrictions error_text, // output buffer - kBufSize, // buf size - NULL); // no arguments for inserts + kBufSize, // buf size + nullptr); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { @@ -1398,7 +1729,7 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT // Utility functions for encoding Unicode text (wide strings) in // UTF-8. -// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding @@ -1436,7 +1767,7 @@ inline UInt32 ChopLowBits(UInt32* bits, int n) { // to "(Invalid Unicode 0xXXXXXXXX)". std::string CodePointToUtf8(UInt32 code_point) { if (code_point > kMaxCodePoint4) { - return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; + return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. @@ -1462,9 +1793,9 @@ std::string CodePointToUtf8(UInt32 code_point) { return str; } -// The following two functions only make sense if the the system +// The following two functions only make sense if the system // uses UTF-16 for wide string encoding. All supported systems -// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. +// with 16 bit wchar_t (Windows, Cygwin) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point @@ -1477,17 +1808,20 @@ inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { + const auto first_u = static_cast(first); + const auto second_u = static_cast(second); const UInt32 mask = (1 << 10) - 1; - return (sizeof(wchar_t) == 2) ? - (((first & mask) << 10) | (second & mask)) + 0x10000 : - // This function should not be called when the condition is - // false, but we provide a sensible default in case it is. - static_cast(first); + return (sizeof(wchar_t) == 2) + ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000 + : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + first_u; } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number @@ -1524,38 +1858,38 @@ std::string WideStringToUtf8(const wchar_t* str, int num_chars) { // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". std::string String::ShowWideCString(const wchar_t * wide_c_str) { - if (wide_c_str == NULL) return "(null)"; + if (wide_c_str == nullptr) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } -// Compares two wide C strings. Returns true iff they have the same -// content. +// Compares two wide C strings. Returns true if and only if they have the +// same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { - if (lhs == NULL) return rhs == NULL; + if (lhs == nullptr) return rhs == nullptr; - if (rhs == NULL) return false; + if (rhs == nullptr) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual) { - if (String::WideCStringEquals(expected, actual)) { +AssertionResult CmpHelperSTREQ(const char* lhs_expression, + const char* rhs_expression, + const wchar_t* lhs, + const wchar_t* rhs) { + if (String::WideCStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), false); } @@ -1574,37 +1908,35 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression, << " vs " << PrintToString(s2); } -// Compares two C strings, ignoring case. Returns true iff they have +// Compares two C strings, ignoring case. Returns true if and only if they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { - if (lhs == NULL) - return rhs == NULL; - if (rhs == NULL) - return false; + if (lhs == nullptr) return rhs == nullptr; + if (rhs == nullptr) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. +// Compares two wide C strings, ignoring case. Returns true if and only if they +// have the same content. +// +// Unlike wcscasecmp(), this function can handle NULL argument(s). +// A NULL C string is considered different to any non-NULL wide C string, +// including the empty string. +// NB: The implementations on different platforms slightly differ. +// On windows, this method uses _wcsicmp which compares according to LC_CTYPE +// environment variable. On GNU platform this method uses wcscasecmp +// which compares according to LC_CTYPE category of the current locale. +// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the +// current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { - if (lhs == NULL) return rhs == NULL; + if (lhs == nullptr) return rhs == nullptr; - if (rhs == NULL) return false; + if (rhs == nullptr) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; @@ -1615,14 +1947,14 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, // Other unknown OSes may not define it either. wint_t left, right; do { - left = towlower(*lhs++); - right = towlower(*rhs++); + left = towlower(static_cast(*lhs++)); + right = towlower(static_cast(*rhs++)); } while (left && left == right); return left == right; #endif // OS selector } -// Returns true iff str ends with the given suffix, ignoring case. +// Returns true if and only if str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. bool String::EndsWithCaseInsensitive( const std::string& str, const std::string& suffix) { @@ -1641,12 +1973,17 @@ std::string String::FormatIntWidth2(int value) { } // Formats an int value as "%X". -std::string String::FormatHexInt(int value) { +std::string String::FormatHexUInt32(UInt32 value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } +// Formats an int value as "%X". +std::string String::FormatHexInt(int value) { + return FormatHexUInt32(static_cast(value)); +} + // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; @@ -1663,7 +2000,7 @@ std::string StringStreamToString(::std::stringstream* ss) { const char* const end = start + str.length(); std::string result; - result.reserve(2 * (end - start)); + result.reserve(static_cast(2 * (end - start))); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; @@ -1693,9 +2030,7 @@ std::string AppendUserMessage(const std::string& gtest_msg, // Creates an empty TestResult. TestResult::TestResult() - : death_test_count_(0), - elapsed_time_(0) { -} + : death_test_count_(0), start_timestamp_(0), elapsed_time_(0) {} // D'tor. TestResult::~TestResult() { @@ -1707,7 +2042,7 @@ TestResult::~TestResult() { const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); - return test_part_results_.at(i); + return test_part_results_.at(static_cast(i)); } // Returns the i-th test property. i can range from 0 to @@ -1716,7 +2051,7 @@ const TestPartResult& TestResult::GetTestPartResult(int i) const { const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); - return test_properties_.at(i); + return test_properties_.at(static_cast(i)); } // Clears the test part results. @@ -1764,23 +2099,18 @@ static const char* const kReservedTestSuitesAttributes[] = { // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { - "disabled", - "errors", - "failures", - "name", - "tests", - "time" -}; + "disabled", "errors", "failures", "name", "tests", "time", "timestamp"}; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { - "classname", - "name", - "status", - "time", - "type_param", - "value_param" -}; + "classname", "name", "status", "time", "type_param", + "value_param", "file", "line"}; + +// Use a slightly different set for allowed output to ensure existing tests can +// still RecordProperty("result") or "RecordProperty(timestamp") +static const char* const kReservedOutputTestCaseAttributes[] = { + "classname", "name", "status", "time", "type_param", + "value_param", "file", "line", "result", "timestamp"}; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { @@ -1802,6 +2132,22 @@ static std::vector GetReservedAttributesForElement( return std::vector(); } +// TODO(jdesprez): Merge the two getReserved attributes once skip is improved +static std::vector GetReservedOutputAttributesForElement( + const std::string& xml_element) { + if (xml_element == "testsuites") { + return ArrayAsVector(kReservedTestSuitesAttributes); + } else if (xml_element == "testsuite") { + return ArrayAsVector(kReservedTestSuiteAttributes); + } else if (xml_element == "testcase") { + return ArrayAsVector(kReservedOutputTestCaseAttributes); + } else { + GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; + } + // This code is unreachable but some compilers may not realizes that. + return std::vector(); +} + static std::string FormatWordList(const std::vector& words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { @@ -1816,8 +2162,9 @@ static std::string FormatWordList(const std::vector& words) { return word_list.GetString(); } -bool ValidateTestPropertyName(const std::string& property_name, - const std::vector& reserved_names) { +static bool ValidateTestPropertyName( + const std::string& property_name, + const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name @@ -1844,7 +2191,17 @@ void TestResult::Clear() { elapsed_time_ = 0; } -// Returns true iff the test failed. +// Returns true off the test part was skipped. +static bool TestPartSkipped(const TestPartResult& result) { + return result.skipped(); +} + +// Returns true if and only if the test was skipped. +bool TestResult::Skipped() const { + return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0; +} + +// Returns true if and only if the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) @@ -1853,22 +2210,22 @@ bool TestResult::Failed() const { return false; } -// Returns true iff the test part fatally failed. +// Returns true if and only if the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } -// Returns true iff the test fatally failed. +// Returns true if and only if the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } -// Returns true iff the test part non-fatally failed. +// Returns true if and only if the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } -// Returns true iff the test has a non-fatal failure. +// Returns true if and only if the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } @@ -1888,14 +2245,15 @@ int TestResult::test_property_count() const { // Creates a Test object. -// The c'tor saves the values of all Google Test flags. +// The c'tor saves the states of all flags. Test::Test() - : gtest_flag_saver_(new internal::GTestFlagSaver) { + : gtest_flag_saver_(new GTEST_FLAG_SAVER_) { } -// The d'tor restores the values of all Google Test flags. +// The d'tor restores the states of all flags. The actual work is +// done by the d'tor of the gtest_flag_saver_ field, and thus not +// visible here. Test::~Test() { - delete gtest_flag_saver_; } // Sets up the test fixture. @@ -1930,25 +2288,25 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, - NULL, // No info about the source file where the exception occurred. - -1, // We have no info on which line caused the exception. + nullptr, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. message, - ""); // No stack trace, either. + ""); // No stack trace, either. } } // namespace internal -// Google Test requires all tests in the same test case to use the same test +// Google Test requires all tests in the same test suite to use the same test // fixture class. This function checks if the current test has the -// same fixture class as the first test in the current test case. If +// same fixture class as the first test in the current test suite. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - const TestCase* const test_case = impl->current_test_case(); + const TestSuite* const test_suite = impl->current_test_suite(); - // Info about the first test in the current test case. - const TestInfo* const first_test_info = test_case->test_info_list()[0]; + // Info about the first test in the current test suite. + const TestInfo* const first_test_info = test_suite->test_info_list()[0]; const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); @@ -1964,8 +2322,8 @@ bool Test::HasSameFixtureClass() { const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { - // The user mixed TEST and TEST_F in this test case - we'll tell - // him/her how to fix it. + // Both TEST and TEST_F appear in same test suite, which is incorrect. + // Tell the user how to fix this. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as @@ -1976,27 +2334,27 @@ bool Test::HasSameFixtureClass() { first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class, so mixing TEST_F and TEST in the same test case is\n" - << "illegal. In test case " << this_test_info->test_case_name() + << "All tests in the same test suite must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test suite is\n" + << "illegal. In test suite " << this_test_info->test_suite_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { - // The user defined two fixture classes with the same name in - // two namespaces - we'll tell him/her how to fix it. + // Two fixture classes with the same name appear in two different + // namespaces, which is not allowed. Tell the user how to fix this. ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " - << this_test_info->test_case_name() << ",\n" - << "you defined test " << first_test_name - << " and test " << this_test_name << "\n" + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " + << this_test_info->test_suite_name() << ",\n" + << "you defined test " << first_test_name << " and test " + << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" - << "of the classes to put the tests into different test cases."; + << "of the classes to put the tests into different test suites."; } return false; } @@ -2029,7 +2387,7 @@ namespace internal { static std::string FormatCxxExceptionMessage(const char* description, const char* location) { Message message; - if (description != NULL) { + if (description != nullptr) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; @@ -2113,6 +2471,8 @@ Result HandleExceptionsInMethodIfSupported( #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const AssertionException&) { // NOLINT + // This failure was reported already. } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing @@ -2125,7 +2485,7 @@ Result HandleExceptionsInMethodIfSupported( } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(NULL, location)); + FormatCxxExceptionMessage(nullptr, location)); } return static_cast(0); #else @@ -2145,8 +2505,9 @@ void Test::Run() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); - // We will run the test only if SetUp() was successful. - if (!HasFatalFailure()) { + // We will run the test only if SetUp() was successful and didn't call + // GTEST_SKIP(). + if (!HasFatalFailure() && !IsSkipped()) { impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "the test body"); @@ -2160,31 +2521,37 @@ void Test::Run() { this, &Test::TearDown, "TearDown()"); } -// Returns true iff the current test has a fatal failure. +// Returns true if and only if the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } -// Returns true iff the current test has a non-fatal failure. +// Returns true if and only if the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } +// Returns true if and only if the current test was skipped. +bool Test::IsSkipped() { + return internal::GetUnitTestImpl()->current_test_result()->Skipped(); +} + // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object. -TestInfo::TestInfo(const std::string& a_test_case_name, - const std::string& a_name, - const char* a_type_param, +TestInfo::TestInfo(const std::string& a_test_suite_name, + const std::string& a_name, const char* a_type_param, const char* a_value_param, + internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) - : test_case_name_(a_test_case_name), + : test_suite_name_(a_test_suite_name), name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - value_param_(a_value_param ? new std::string(a_value_param) : NULL), + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), + value_param_(a_value_param ? new std::string(a_value_param) : nullptr), + location_(a_code_location), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), @@ -2202,53 +2569,48 @@ namespace internal { // // Arguments: // -// test_case_name: name of the test case +// test_suite_name: name of the test suite // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. +// code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory) { + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = - new TestInfo(test_case_name, name, type_param, value_param, - fixture_class_id, factory); + new TestInfo(test_suite_name, name, type_param, value_param, + code_location, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } -#if GTEST_HAS_PARAM_TEST -void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line) { +void ReportInvalidTestSuiteType(const char* test_suite_name, + CodeLocation code_location) { Message errors; errors - << "Attempted redefinition of test case " << test_case_name << ".\n" - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " << test_case_name << ", you tried\n" + << "Attempted redefinition of test suite " << test_suite_name << ".\n" + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " << test_suite_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" - << "test cases."; + << "test suites."; - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors.GetString().c_str()); + GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(), + code_location.line) + << " " << errors.GetString(); } -#endif // GTEST_HAS_PARAM_TEST - } // namespace internal namespace { @@ -2256,7 +2618,7 @@ namespace { // A predicate that checks the test name of a TestInfo against a known // value. // -// This is used for implementation of the TestCase class only. We put +// This is used for implementation of the TestSuite class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // @@ -2269,7 +2631,7 @@ class TestNameIs { explicit TestNameIs(const char* name) : name_(name) {} - // Returns true iff the test name of test_info matches name_. + // Returns true if and only if the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && test_info->name() == name_; } @@ -2283,15 +2645,13 @@ class TestNameIs { namespace internal { // This method expands all parameterized tests registered with macros TEST_P -// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// and INSTANTIATE_TEST_SUITE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { -#if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } -#endif } } // namespace internal @@ -2319,19 +2679,23 @@ void TestInfo::Run() { factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); - // Runs the test only if the test object was created and its - // constructor didn't generate a fatal failure. - if ((test != NULL) && !Test::HasFatalFailure()) { + // Runs the test if the constructor didn't generate a fatal failure or invoke + // GTEST_SKIP(). + // Note that the object will not be null + if (!Test::HasFatalFailure() && !Test::IsSkipped()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } - // Deletes the test object. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - test, &Test::DeleteSelf_, "the test fixture's destructor"); + if (test != nullptr) { + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); + } + result_.set_start_timestamp(start); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. @@ -2339,134 +2703,151 @@ void TestInfo::Run() { // Tells UnitTest to stop associating assertion results to this // test. - impl->set_current_test_info(NULL); + impl->set_current_test_info(nullptr); } -// class TestCase +// class TestSuite -// Gets the number of successful tests in this test case. -int TestCase::successful_test_count() const { +// Gets the number of successful tests in this test suite. +int TestSuite::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } -// Gets the number of failed tests in this test case. -int TestCase::failed_test_count() const { +// Gets the number of successful tests in this test suite. +int TestSuite::skipped_test_count() const { + return CountIf(test_info_list_, TestSkipped); +} + +// Gets the number of failed tests in this test suite. +int TestSuite::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } // Gets the number of disabled tests that will be reported in the XML report. -int TestCase::reportable_disabled_test_count() const { +int TestSuite::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } -// Gets the number of disabled tests in this test case. -int TestCase::disabled_test_count() const { +// Gets the number of disabled tests in this test suite. +int TestSuite::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. -int TestCase::reportable_test_count() const { +int TestSuite::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } -// Get the number of tests in this test case that should run. -int TestCase::test_to_run_count() const { +// Get the number of tests in this test suite that should run. +int TestSuite::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. -int TestCase::total_test_count() const { +int TestSuite::total_test_count() const { return static_cast(test_info_list_.size()); } -// Creates a TestCase with the given name. +// Creates a TestSuite with the given name. // // Arguments: // -// name: name of the test case -// a_type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* a_name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) +// name: name of the test suite +// a_type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite::TestSuite(const char* a_name, const char* a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) : name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), - elapsed_time_(0) { -} + start_timestamp_(0), + elapsed_time_(0) {} -// Destructor of TestCase. -TestCase::~TestCase() { +// Destructor of TestSuite. +TestSuite::~TestSuite() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. -const TestInfo* TestCase::GetTestInfo(int i) const { +const TestInfo* TestSuite::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; + return index < 0 ? nullptr : test_info_list_[static_cast(index)]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. -TestInfo* TestCase::GetMutableTestInfo(int i) { +TestInfo* TestSuite::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; + return index < 0 ? nullptr : test_info_list_[static_cast(index)]; } -// Adds a test to this test case. Will delete the test upon -// destruction of the TestCase object. -void TestCase::AddTestInfo(TestInfo * test_info) { +// Adds a test to this test suite. Will delete the test upon +// destruction of the TestSuite object. +void TestSuite::AddTestInfo(TestInfo* test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } -// Runs every test in this TestCase. -void TestCase::Run() { +// Runs every test in this TestSuite. +void TestSuite::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_case(this); + impl->set_current_test_suite(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + // Call both legacy and the new API + repeater->OnTestSuiteStart(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseStart(*this); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()"); - const internal::TimeInMillis start = internal::GetTimeInMillis(); + start_timestamp_ = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } - elapsed_time_ = internal::GetTimeInMillis() - start; + elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()"); + // Call both legacy and the new API + repeater->OnTestSuiteEnd(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseEnd(*this); - impl->set_current_test_case(NULL); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + + impl->set_current_test_suite(nullptr); } -// Clears the results of all tests in this test case. -void TestCase::ClearResult() { +// Clears the results of all tests in this test suite. +void TestSuite::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } -// Shuffles the tests in this test case. -void TestCase::ShuffleTests(internal::Random* random) { +// Shuffles the tests in this test suite. +void TestSuite::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. -void TestCase::UnshuffleTests() { +void TestSuite::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } @@ -2489,9 +2870,9 @@ static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } -// Formats the count of test cases. -static std::string FormatTestCaseCount(int test_case_count) { - return FormatCountableNoun(test_case_count, "test case", "test cases"); +// Formats the count of test suites. +static std::string FormatTestSuiteCount(int test_suite_count) { + return FormatCountableNoun(test_suite_count, "test suite", "test suites"); } // Converts a TestPartResult::Type enum to human-friendly string @@ -2500,6 +2881,8 @@ static std::string FormatTestCaseCount(int test_case_count) { // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { + case TestPartResult::kSkip: + return "Skipped"; case TestPartResult::kSuccess: return "Success"; @@ -2547,18 +2930,11 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) { } // class PrettyUnitTestResultPrinter - -enum GTestColor { - COLOR_DEFAULT, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW -}; - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW // Returns the character attribute for the given color. -WORD GetColorAttribute(GTestColor color) { +static WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; @@ -2567,27 +2943,59 @@ WORD GetColorAttribute(GTestColor color) { } } +static int GetBitOffset(WORD color_mask) { + if (color_mask == 0) return 0; + + int bitOffset = 0; + while ((color_mask & 1) == 0) { + color_mask >>= 1; + ++bitOffset; + } + return bitOffset; +} + +static WORD GetNewColor(GTestColor color, WORD old_color_attrs) { + // Let's reuse the BG + static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY; + static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED | FOREGROUND_INTENSITY; + const WORD existing_bg = old_color_attrs & background_mask; + + WORD new_color = + GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY; + static const int bg_bitOffset = GetBitOffset(background_mask); + static const int fg_bitOffset = GetBitOffset(foreground_mask); + + if (((new_color & background_mask) >> bg_bitOffset) == + ((new_color & foreground_mask) >> fg_bitOffset)) { + new_color ^= FOREGROUND_INTENSITY; // invert intensity + } + return new_color; +} + #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. -const char* GetAnsiColorCode(GTestColor color) { +static const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; - default: return NULL; - }; + default: + return nullptr; + } } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE -// Returns true iff Google Test should use colors in the output. +// Returns true if and only if Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; @@ -2600,6 +3008,10 @@ bool ShouldUseColor(bool stdout_is_tty) { String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || String::CStringEquals(term, "screen-256color") || + String::CStringEquals(term, "tmux") || + String::CStringEquals(term, "tmux-256color") || + String::CStringEquals(term, "rxvt-unicode") || + String::CStringEquals(term, "rxvt-unicode-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; @@ -2623,14 +3035,14 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS - const bool use_color = false; +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS || GTEST_OS_IOS || \ + GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM) + const bool use_color = AlwaysFalse(); #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); -#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - // The '!= 0' comparison is necessary to satisfy MSVC 7.1. +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS if (!use_color) { vprintf(fmt, args); @@ -2638,20 +3050,22 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; + const WORD new_color = GetNewColor(color, old_color_attrs); // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); - SetConsoleTextAttribute(stdout_handle, - GetColorAttribute(color) | FOREGROUND_INTENSITY); + SetConsoleTextAttribute(stdout_handle, new_color); + vprintf(fmt, args); fflush(stdout); @@ -2665,23 +3079,22 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_end(args); } -// Text printed in Google Test's text output and --gunit_list_tests +// Text printed in Google Test's text output and --gtest_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; -void PrintFullTestCommentIfPresent(const TestInfo& test_info) { +static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); - if (type_param != NULL || value_param != NULL) { + if (type_param != nullptr || value_param != nullptr) { printf(", where "); - if (type_param != NULL) { + if (type_param != nullptr) { printf("%s = %s", kTypeParamLabel, type_param); - if (value_param != NULL) - printf(" and "); + if (value_param != nullptr) printf(" and "); } - if (value_param != NULL) { + if (value_param != nullptr) { printf("%s = %s", kValueParamLabel, value_param); } } @@ -2693,27 +3106,39 @@ void PrintFullTestCommentIfPresent(const TestInfo& test_info) { class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} - static void PrintTestName(const char * test_case, const char * test) { - printf("%s.%s", test_case, test); + static void PrintTestName(const char* test_suite, const char* test) { + printf("%s.%s", test_suite, test); } // The following methods override what's in the TestEventListener class. - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& test_case) override; +#else + void OnTestSuiteStart(const TestSuite& test_suite) override; +#endif // OnTestCaseStart + + void OnTestStart(const TestInfo& test_info) override; + + void OnTestPartResult(const TestPartResult& result) override; + void OnTestEnd(const TestInfo& test_info) override; +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& test_case) override; +#else + void OnTestSuiteEnd(const TestSuite& test_suite) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} private: static void PrintFailedTests(const UnitTest& unit_test); + static void PrintSkippedTests(const UnitTest& unit_test); }; // Fired before each iteration of tests starts. @@ -2748,7 +3173,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationStart( ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); fflush(stdout); } @@ -2759,22 +3184,38 @@ void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( fflush(stdout); } +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); - if (test_case.type_param() == NULL) { + if (test_case.type_param() == nullptr) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } +#else +void PrettyUnitTestResultPrinter::OnTestSuiteStart( + const TestSuite& test_suite) { + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_suite.name()); + if (test_suite.type_param() == nullptr) { + printf("\n"); + } else { + printf(", where %s = %s\n", kTypeParamLabel, test_suite.type_param()); + } + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_info.test_case_name(), test_info.name()); + PrintTestName(test_info.test_suite_name(), test_info.name()); printf("\n"); fflush(stdout); } @@ -2782,22 +3223,29 @@ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { - // If the test part succeeded, we don't need to do anything. - if (result.type() == TestPartResult::kSuccess) - return; - - // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(result); - fflush(stdout); + switch (result.type()) { + // If the test part succeeded, or was skipped, + // we don't need to do anything. + case TestPartResult::kSkip: + case TestPartResult::kSuccess: + return; + default: + // Print failure message from the assertion + // (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); + } } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else if (test_info.result()->Skipped()) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } - PrintTestName(test_info.test_case_name(), test_info.name()); + PrintTestName(test_info.test_suite_name(), test_info.name()); if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); @@ -2810,17 +3258,29 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { fflush(stdout); } +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s (%s ms total)\n\n", - counts.c_str(), test_case.name(), + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } +#else +void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) { + if (!GTEST_FLAG(print_time)) return; + + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(), + internal::StreamableToString(test_suite.elapsed_time()).c_str()); + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { @@ -2836,30 +3296,54 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { return; } - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - const TestCase& test_case = *unit_test.GetTestCase(i); - if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite& test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.failed_test_count() == 0)) { continue; } - for (int j = 0; j < test_case.total_test_count(); ++j) { - const TestInfo& test_info = *test_case.GetTestInfo(j); - if (!test_info.should_run() || test_info.result()->Passed()) { + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo& test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Failed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s", test_case.name(), test_info.name()); + printf("%s.%s", test_suite.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } } -void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { +// Internal helper for printing the list of skipped tests. +void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) { + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite& test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.skipped_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo& test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Skipped()) { + continue; + } + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s.%s", test_suite.name(), test_info.name()); + printf("\n"); + } + } +} + +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); @@ -2868,6 +3352,13 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count > 0) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str()); + PrintSkippedTests(unit_test); + } + int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); @@ -2900,7 +3391,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} - virtual ~TestEventRepeater(); + ~TestEventRepeater() override; void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); @@ -2909,19 +3400,27 @@ class TestEventRepeater : public TestEventListener { bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& unit_test); + void OnTestProgramStart(const UnitTest& unit_test) override; + void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestSuite& parameter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteStart(const TestSuite& parameter) override; + void OnTestStart(const TestInfo& test_info) override; + void OnTestPartResult(const TestPartResult& result) override; + void OnTestEnd(const TestInfo& test_info) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& parameter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteEnd(const TestSuite& parameter) override; + void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) override; + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest& unit_test) override; private: // Controls whether events will be forwarded to listeners_. Set to false @@ -2941,16 +3440,15 @@ void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } -// TODO(vladl@google.com): Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { - listeners_.erase(listeners_.begin() + i); + listeners_.erase(listeners_.begin() + static_cast(i)); return listener; } } - return NULL; + return nullptr; } // Since most methods are very similar, use macros to reduce boilerplate. @@ -2965,25 +3463,33 @@ void TestEventRepeater::Name(const Type& parameter) { \ } // This defines a member that forwards the call to all listeners in reverse // order. -#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ + void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = listeners_.size(); i != 0; i--) { \ + listeners_[i - 1]->Name(parameter); \ + } \ + } \ + } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) -GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestSuiteEnd, TestSuite) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ @@ -3001,8 +3507,8 @@ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { - listeners_[i]->OnTestIterationEnd(unit_test, iteration); + for (size_t i = listeners_.size(); i > 0; i--) { + listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration); } } } @@ -3014,7 +3520,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void ListTestsMatchingFilter(const std::vector& test_suites); + + // Prints an XML summary of all unit tests. + static void PrintXmlTestsList(std::ostream* stream, + const std::vector& test_suites); private: // Is c a whitespace character that is normalized to a space character @@ -3059,12 +3570,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, + const char* test_suite_name, const TestInfo& test_info); - // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(::std::ostream* stream, - const TestCase& test_case); + // Prints an XML representation of a TestSuite object + static void PrintXmlTestSuite(::std::ostream* stream, + const TestSuite& test_suite); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(::std::ostream* stream, @@ -3076,6 +3587,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); + // Streams an XML representation of the test properties of a TestResult + // object. + static void OutputXmlTestProperties(std::ostream* stream, + const TestResult& result); + // The output file. const std::string output_file_; @@ -3085,46 +3601,30 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { - if (output_file_.c_str() == NULL || output_file_.empty()) { - fprintf(stderr, "XML output file may not be null\n"); - fflush(stderr); - exit(EXIT_FAILURE); + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "XML output file may not be null"; } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // TODO(wan): report the reason of the failure. - // - // We don't do it for now as: - // - // 1. There is no urgent need for it. - // 2. It's a bit involved to make the errno variable thread-safe on - // all three operating systems (Linux, Windows, and Mac OS). - // 3. To interpret the meaning of errno in a thread-safe way, - // we need the strerror_r() function, which is not available on - // Windows. - fprintf(stderr, - "Unable to open file \"%s\"\n", - output_file_.c_str()); - fflush(stderr); - exit(EXIT_FAILURE); - } + FILE* xmlout = OpenFileForWriting(output_file_); std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } +void XmlUnitTestResultPrinter::ListTestsMatchingFilter( + const std::vector& test_suites) { + FILE* xmlout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintXmlTestsList(&stream, test_suites); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); + fclose(xmlout); +} + // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character @@ -3135,8 +3635,6 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. -// TODO(wan): It might be nice to have a minimally invasive, human-readable -// escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { Message m; @@ -3196,11 +3694,12 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // The following routines generate an XML representation of a UnitTest // object. +// GOOGLETEST_CM0009 DO NOT DELETE // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object -// <-- corresponds to a TestCase object +// <-- corresponds to a TestSuite object // <-- corresponds to a TestInfo object // ... // ... @@ -3213,34 +3712,38 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; - ss << ms/1000.0; + ss << (static_cast(ms) * 1e-3); return ss.str(); } -// Converts the given epoch time in milliseconds to a date string in the ISO -// 8601 format, without the timezone information. -std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { - // Using non-reentrant version as localtime_r is not portable. - time_t seconds = static_cast(ms / 1000); -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996 - // (function or variable may be unsafe). - const struct tm* const time_struct = localtime(&seconds); // NOLINT -# pragma warning(pop) // Restores the warning state again. +static bool PortableLocaltime(time_t seconds, struct tm* out) { +#if defined(_MSC_VER) + return localtime_s(out, &seconds) == 0; +#elif defined(__MINGW32__) || defined(__MINGW64__) + // MINGW provides neither localtime_r nor localtime_s, but uses + // Windows' localtime(), which has a thread-local tm buffer. + struct tm* tm_ptr = localtime(&seconds); // NOLINT + if (tm_ptr == nullptr) return false; + *out = *tm_ptr; + return true; #else - const struct tm* const time_struct = localtime(&seconds); // NOLINT + return localtime_r(&seconds, out) != nullptr; #endif - if (time_struct == NULL) - return ""; // Invalid ms value +} +// Converts the given epoch time in milliseconds to a date string in the ISO +// 8601 format, without the timezone information. +std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { + struct tm time_struct; + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; // YYYY-MM-DDThh:mm:ss - return StreamableToString(time_struct->tm_year + 1900) + "-" + - String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + - String::FormatIntWidth2(time_struct->tm_mday) + "T" + - String::FormatIntWidth2(time_struct->tm_hour) + ":" + - String::FormatIntWidth2(time_struct->tm_min) + ":" + - String::FormatIntWidth2(time_struct->tm_sec); + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. @@ -3250,7 +3753,7 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, *stream << ""); - if (next_segment != NULL) { + if (next_segment != nullptr) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>& allowed_names = - GetReservedAttributesForElement(element_name); + GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) @@ -3280,30 +3783,47 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute( } // Prints an XML representation of a TestInfo object. -// TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, + const char* test_suite_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); - const std::string kTestcase = "testcase"; + const std::string kTestsuite = "testcase"; + + if (test_info.is_in_another_shard()) { + return; + } *stream << " \n"; + return; } - OutputXmlAttribute(stream, kTestcase, "status", + OutputXmlAttribute(stream, kTestsuite, "status", test_info.should_run() ? "run" : "notrun"); - OutputXmlAttribute(stream, kTestcase, "time", + OutputXmlAttribute(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "skipped" : "completed") + : "suppressed"); + OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(result.elapsed_time())); - OutputXmlAttribute(stream, kTestcase, "classname", test_case_name); - *stream << TestPropertiesAsXmlAttributes(result); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); + OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { @@ -3312,46 +3832,56 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, if (++failures == 1) { *stream << ">\n"; } - const string location = internal::FormatCompilerIndependentFileLocation( - part.file_name(), part.line_number()); - const string summary = location + "\n" + part.summary(); + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string summary = location + "\n" + part.summary(); *stream << " "; - const string detail = location + "\n" + part.message(); + const std::string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } - if (failures == 0) + if (failures == 0 && result.test_property_count() == 0) { *stream << " />\n"; - else + } else { + if (failures == 0) { + *stream << ">\n"; + } + OutputXmlTestProperties(stream, result); *stream << " \n"; + } } -// Prints an XML representation of a TestCase object -void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, - const TestCase& test_case) { +// Prints an XML representation of a TestSuite object +void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream, + const TestSuite& test_suite) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; - OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); + OutputXmlAttribute(stream, kTestsuite, "name", test_suite.name()); OutputXmlAttribute(stream, kTestsuite, "tests", - StreamableToString(test_case.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuite, "errors", "0"); - OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) - << ">\n"; - - for (int i = 0; i < test_case.total_test_count(); ++i) { - if (test_case.GetTestInfo(i)->is_reportable()) - OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + StreamableToString(test_suite.reportable_test_count())); + if (!GTEST_FLAG(list_tests)) { + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_suite.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_suite.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_suite.elapsed_time())); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp())); + *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result()); + } + *stream << ">\n"; + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) + OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } *stream << " \n"; } @@ -3372,25 +3902,46 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); + OutputXmlAttribute(stream, kTestsuites, "time", + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); - OutputXmlAttribute(stream, kTestsuites, "time", - FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } - *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - if (unit_test.GetTestCase(i)->reportable_test_count() > 0) - PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) + PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i)); + } + *stream << "\n"; +} + +void XmlUnitTestResultPrinter::PrintXmlTestsList( + std::ostream* stream, const std::vector& test_suites) { + const std::string kTestsuites = "testsuites"; + + *stream << "\n"; + *stream << "<" << kTestsuites; + + int total_tests = 0; + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); + } + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(total_tests)); + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + for (auto test_suite : test_suites) { + PrintXmlTestSuite(stream, *test_suite); } *stream << "\n"; } @@ -3408,8 +3959,403 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( return attributes.GetString(); } +void XmlUnitTestResultPrinter::OutputXmlTestProperties( + std::ostream* stream, const TestResult& result) { + const std::string kProperties = "properties"; + const std::string kProperty = "property"; + + if (result.test_property_count() <= 0) { + return; + } + + *stream << "<" << kProperties << ">\n"; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + *stream << "<" << kProperty; + *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; + *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; + *stream << "/>\n"; + } + *stream << "\n"; +} + // End XmlUnitTestResultPrinter +// This class generates an JSON output file. +class JsonUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit JsonUnitTestResultPrinter(const char* output_file); + + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + + // Prints an JSON summary of all unit tests. + static void PrintJsonTestList(::std::ostream* stream, + const std::vector& test_suites); + + private: + // Returns an JSON-escaped copy of the input string str. + static std::string EscapeJson(const std::string& str); + + //// Verifies that the given attribute belongs to the given element and + //// streams the attribute as JSON. + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma = true); + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma = true); + + // Streams a JSON representation of a TestInfo object. + static void OutputJsonTestInfo(::std::ostream* stream, + const char* test_suite_name, + const TestInfo& test_info); + + // Prints a JSON representation of a TestSuite object + static void PrintJsonTestSuite(::std::ostream* stream, + const TestSuite& test_suite); + + // Prints a JSON summary of unit_test to output stream out. + static void PrintJsonUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as + // a JSON dictionary. + static std::string TestPropertiesAsJson(const TestResult& result, + const std::string& indent); + + // The output file. + const std::string output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(JsonUnitTestResultPrinter); +}; + +// Creates a new JsonUnitTestResultPrinter. +JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "JSON output file may not be null"; + } +} + +void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* jsonout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintJsonUnitTest(&stream, unit_test); + fprintf(jsonout, "%s", StringStreamToString(&stream).c_str()); + fclose(jsonout); +} + +// Returns an JSON-escaped copy of the input string str. +std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) { + Message m; + + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '\\': + case '"': + case '/': + m << '\\' << ch; + break; + case '\b': + m << "\\b"; + break; + case '\t': + m << "\\t"; + break; + case '\n': + m << "\\n"; + break; + case '\f': + m << "\\f"; + break; + case '\r': + m << "\\r"; + break; + default: + if (ch < ' ') { + m << "\\u00" << String::FormatByte(static_cast(ch)); + } else { + m << ch; + } + break; + } + } + + return m.GetString(); +} + +// The following routines generate an JSON representation of a UnitTest +// object. + +// Formats the given time in milliseconds as seconds. +static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) { + ::std::stringstream ss; + ss << (static_cast(ms) * 1e-3) << "s"; + return ss.str(); +} + +// Converts the given epoch time in milliseconds to a date string in the +// RFC3339 format, without the timezone information. +static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) { + struct tm time_struct; + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec) + "Z"; +} + +static inline std::string Indent(size_t width) { + return std::string(width, ' '); +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedOutputAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\""; + if (comma) + *stream << ",\n"; +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedOutputAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": " << StreamableToString(value); + if (comma) + *stream << ",\n"; +} + +// Prints a JSON representation of a TestInfo object. +void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, + const char* test_suite_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const std::string kTestsuite = "testcase"; + const std::string kIndent = Indent(10); + + *stream << Indent(8) << "{\n"; + OutputJsonKey(stream, kTestsuite, "name", test_info.name(), kIndent); + + if (test_info.value_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "value_param", test_info.value_param(), + kIndent); + } + if (test_info.type_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "type_param", test_info.type_param(), + kIndent); + } + if (GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "file", test_info.file(), kIndent); + OutputJsonKey(stream, kTestsuite, "line", test_info.line(), kIndent, false); + *stream << "\n" << Indent(8) << "}"; + return; + } + + OutputJsonKey(stream, kTestsuite, "status", + test_info.should_run() ? "RUN" : "NOTRUN", kIndent); + OutputJsonKey(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "SKIPPED" : "COMPLETED") + : "SUPPRESSED", + kIndent); + OutputJsonKey(stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent); + OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent, + false); + *stream << TestPropertiesAsJson(result, kIndent); + + int failures = 0; + for (int i = 0; i < result.total_part_count(); ++i) { + const TestPartResult& part = result.GetTestPartResult(i); + if (part.failed()) { + *stream << ",\n"; + if (++failures == 1) { + *stream << kIndent << "\"" << "failures" << "\": [\n"; + } + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string message = EscapeJson(location + "\n" + part.message()); + *stream << kIndent << " {\n" + << kIndent << " \"failure\": \"" << message << "\",\n" + << kIndent << " \"type\": \"\"\n" + << kIndent << " }"; + } + } + + if (failures > 0) + *stream << "\n" << kIndent << "]"; + *stream << "\n" << Indent(8) << "}"; +} + +// Prints an JSON representation of a TestSuite object +void JsonUnitTestResultPrinter::PrintJsonTestSuite( + std::ostream* stream, const TestSuite& test_suite) { + const std::string kTestsuite = "testsuite"; + const std::string kIndent = Indent(6); + + *stream << Indent(4) << "{\n"; + OutputJsonKey(stream, kTestsuite, "name", test_suite.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "tests", test_suite.reportable_test_count(), + kIndent); + if (!GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "failures", + test_suite.failed_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "disabled", + test_suite.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); + OutputJsonKey( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(test_suite.elapsed_time()), + kIndent, false); + *stream << TestPropertiesAsJson(test_suite.ad_hoc_test_result(), kIndent) + << ",\n"; + } + + *stream << kIndent << "\"" << kTestsuite << "\": [\n"; + + bool comma = false; + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); + } + } + *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; +} + +// Prints a JSON summary of unit_test to output stream out. +void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + + OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "disabled", + unit_test.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent); + if (GTEST_FLAG(shuffle)) { + OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(), + kIndent); + } + OutputJsonKey(stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuites, "time", + FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent, + false); + + *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent) + << ",\n"; + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + bool comma = false; + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + PrintJsonTestSuite(stream, *unit_test.GetTestSuite(i)); + } + } + + *stream << "\n" << kIndent << "]\n" << "}\n"; +} + +void JsonUnitTestResultPrinter::PrintJsonTestList( + std::ostream* stream, const std::vector& test_suites) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + int total_tests = 0; + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); + } + OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent); + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + for (size_t i = 0; i < test_suites.size(); ++i) { + if (i != 0) { + *stream << ",\n"; + } + PrintJsonTestSuite(stream, *test_suites[i]); + } + + *stream << "\n" + << kIndent << "]\n" + << "}\n"; +} +// Produces a string representing the test properties in a result as +// a JSON dictionary. +std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( + const TestResult& result, const std::string& indent) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << ",\n" << indent << "\"" << property.key() << "\": " + << "\"" << EscapeJson(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End JsonUnitTestResultPrinter + #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, @@ -3417,8 +4363,8 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. -string StreamingListener::UrlEncode(const char* str) { - string result; +std::string StreamingListener::UrlEncode(const char* str) { + std::string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { @@ -3444,7 +4390,7 @@ void StreamingListener::SocketWriter::MakeConnection() { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; - addrinfo* servinfo = NULL; + addrinfo* servinfo = nullptr; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. @@ -3456,7 +4402,7 @@ void StreamingListener::SocketWriter::MakeConnection() { } // Loop through all the results and connect to the first we can. - for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr; cur_addr = cur_addr->ai_next) { sockfd_ = socket( cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); @@ -3480,58 +4426,82 @@ void StreamingListener::SocketWriter::MakeConnection() { // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ -// Class ScopedTrace +// class OsStackTraceGetter -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message = message.GetString(); +const char* const OsStackTraceGetterInterface::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; - UnitTest::GetInstance()->PushGTestTrace(trace); -} +std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) + GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + std::string result; -// Pops the info pushed by the c'tor. -ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - UnitTest::GetInstance()->PopGTestTrace(); -} + if (max_depth <= 0) { + return result; + } + max_depth = std::min(max_depth, kMaxStackTraceDepth); -// class OsStackTraceGetter + std::vector raw_stack(max_depth); + // Skips the frames requested by the caller, plus this function. + const int raw_stack_size = + absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1); -// Returns the current OS stack trace as an std::string. Parameters: -// -// max_depth - the maximum number of stack frames to be included -// in the trace. -// skip_count - the number of top frames to be skipped; doesn't count -// against max_depth. -// -string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, - int /* skip_count */) - GTEST_LOCK_EXCLUDED_(mutex_) { + void* caller_frame = nullptr; + { + MutexLock lock(&mutex_); + caller_frame = caller_frame_; + } + + for (int i = 0; i < raw_stack_size; ++i) { + if (raw_stack[i] == caller_frame && + !GTEST_FLAG(show_internal_stack_frames)) { + // Add a marker to the trace and stop adding frames. + absl::StrAppend(&result, kElidedFramesMarker, "\n"); + break; + } + + char tmp[1024]; + const char* symbol = "(unknown)"; + if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) { + symbol = tmp; + } + + char line[1024]; + snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol); + result += line; + } + + return result; + +#else // !GTEST_HAS_ABSL + static_cast(max_depth); + static_cast(skip_count); return ""; +#endif // GTEST_HAS_ABSL } -void OsStackTraceGetter::UponLeavingGTest() - GTEST_LOCK_EXCLUDED_(mutex_) { -} +void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + void* caller_frame = nullptr; + if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) { + caller_frame = nullptr; + } -const char* const -OsStackTraceGetter::kElidedFramesMarker = - "... " GTEST_NAME_ " internal frames ..."; + MutexLock lock(&mutex_); + caller_frame_ = caller_frame; +#endif // GTEST_HAS_ABSL +} // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) - : premature_exit_filepath_(premature_exit_filepath) { + : premature_exit_filepath_(premature_exit_filepath ? + premature_exit_filepath : "") { // If a path to the premature-exit file is specified... - if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { + if (!premature_exit_filepath_.empty()) { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. @@ -3542,13 +4512,18 @@ class ScopedPrematureExitFile { } ~ScopedPrematureExitFile() { - if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { - remove(premature_exit_filepath_); + if (!premature_exit_filepath_.empty()) { + int retval = remove(premature_exit_filepath_.c_str()); + if (retval) { + GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \"" + << premature_exit_filepath_ << "\" with error " + << retval; + } } } private: - const char* const premature_exit_filepath_; + const std::string premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; @@ -3559,9 +4534,8 @@ class ScopedPrematureExitFile { TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), - default_result_printer_(NULL), - default_xml_generator_(NULL) { -} + default_result_printer_(nullptr), + default_xml_generator_(nullptr) {} TestEventListeners::~TestEventListeners() { delete repeater_; } @@ -3578,9 +4552,9 @@ void TestEventListeners::Append(TestEventListener* listener) { // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) - default_result_printer_ = NULL; + default_result_printer_ = nullptr; else if (listener == default_xml_generator_) - default_xml_generator_ = NULL; + default_xml_generator_ = nullptr; return repeater_->Release(listener); } @@ -3599,8 +4573,7 @@ void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { // list. delete Release(default_result_printer_); default_result_printer_ = listener; - if (listener != NULL) - Append(listener); + if (listener != nullptr) Append(listener); } } @@ -3615,8 +4588,7 @@ void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; - if (listener != NULL) - Append(listener); + if (listener != nullptr) Append(listener); } } @@ -3640,52 +4612,66 @@ void TestEventListeners::SuppressEventForwarding() { // call this before main() starts, from which point on the return // value will never change. UnitTest* UnitTest::GetInstance() { - // When compiled with MSVC 7.1 in optimized mode, destroying the - // UnitTest object upon exiting the program messes up the exit code, - // causing successful tests to appear failed. We have to use a - // different implementation in this case to bypass the compiler bug. - // This implementation makes the compiler happy, at the cost of - // leaking the UnitTest object. - // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. -#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +#if defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; -#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +#endif // defined(__BORLANDC__) } -// Gets the number of successful test cases. -int UnitTest::successful_test_case_count() const { - return impl()->successful_test_case_count(); +// Gets the number of successful test suites. +int UnitTest::successful_test_suite_count() const { + return impl()->successful_test_suite_count(); } -// Gets the number of failed test cases. -int UnitTest::failed_test_case_count() const { - return impl()->failed_test_case_count(); +// Gets the number of failed test suites. +int UnitTest::failed_test_suite_count() const { + return impl()->failed_test_suite_count(); } -// Gets the number of all test cases. -int UnitTest::total_test_case_count() const { - return impl()->total_test_case_count(); +// Gets the number of all test suites. +int UnitTest::total_test_suite_count() const { + return impl()->total_test_suite_count(); } -// Gets the number of all test cases that contain at least one test +// Gets the number of all test suites that contain at least one test // that should run. +int UnitTest::test_suite_to_run_count() const { + return impl()->test_suite_to_run_count(); +} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_suite_count(); +} +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_suite_count(); +} +int UnitTest::total_test_case_count() const { + return impl()->total_test_suite_count(); +} int UnitTest::test_case_to_run_count() const { - return impl()->test_case_to_run_count(); + return impl()->test_suite_to_run_count(); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } +// Gets the number of skipped tests. +int UnitTest::skipped_test_count() const { + return impl()->skipped_test_count(); +} + // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } @@ -3721,29 +4707,37 @@ internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } -// Returns true iff the unit test passed (i.e. all test cases passed). +// Returns true if and only if the unit test passed (i.e. all test suites +// passed). bool UnitTest::Passed() const { return impl()->Passed(); } -// Returns true iff the unit test failed (i.e. some test case failed -// or something outside of all tests failed). +// Returns true if and only if the unit test failed (i.e. some test suite +// failed or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +const TestSuite* UnitTest::GetTestSuite(int i) const { + return impl()->GetTestSuite(i); +} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the TestResult containing information on test failures and -// properties logged outside of individual test cases. +// properties logged outside of individual test suites. const TestResult& UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -TestCase* UnitTest::GetMutableTestCase(int i) { - return impl()->GetMutableTestCase(i); +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +TestSuite* UnitTest::GetMutableTestSuite(int i) { + return impl()->GetMutableSuiteCase(i); } // Returns the list of event listeners that can be used to track events @@ -3763,8 +4757,8 @@ TestEventListeners& UnitTest::listeners() { // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { - if (env == NULL) { - return NULL; + if (env == nullptr) { + return nullptr; } impl_->environments().push_back(env); @@ -3788,42 +4782,45 @@ void UnitTest::AddTestPartResult( if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; - for (int i = static_cast(impl_->gtest_trace_stack().size()); - i > 0; --i) { + for (size_t i = impl_->gtest_trace_stack().size(); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } - if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + if (os_stack_trace.c_str() != nullptr && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } - const TestPartResult result = - TestPartResult(result_type, file_name, line_number, - msg.GetString().c_str()); + const TestPartResult result = TestPartResult( + result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); - if (result_type != TestPartResult::kSuccess) { + if (result_type != TestPartResult::kSuccess && + result_type != TestPartResult::kSkip) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); +#elif (!defined(__native_client__)) && \ + ((defined(__clang__) || defined(__GNUC__)) && \ + (defined(__x86_64__) || defined(__i386__))) + // with clang/gcc we can achieve the same effect on x86 by invoking int3 + asm("int3"); #else - // Dereference NULL through a volatile pointer to prevent the compiler + // Dereference nullptr through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for - // portability: Symbian doesn't implement abort() well, and some debuggers - // don't correctly trap abort(). - *static_cast(NULL) = 1; + // portability: some debuggers don't correctly trap abort(). + *static_cast(nullptr) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS @@ -3838,8 +4835,8 @@ void UnitTest::AddTestPartResult( } // Adds a TestProperty to the current TestResult object when invoked from -// inside a test, to current TestCase's ad_hoc_test_result_ when invoked -// from SetUpTestCase or TearDownTestCase, or to the global property set +// inside a test, to current TestSuite's ad_hoc_test_result_ when invoked +// from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void UnitTest::RecordProperty(const std::string& key, @@ -3878,20 +4875,21 @@ int UnitTest::Run() { // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( - in_death_test_child_process ? - NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); + in_death_test_child_process + ? nullptr + : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); -#if GTEST_HAS_SEH +#if GTEST_OS_WINDOWS // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { -# if !GTEST_OS_WINDOWS_MOBILE +# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -3904,25 +4902,29 @@ int UnitTest::Run() { _set_error_mode(_OUT_TO_STDERR); # endif -# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +# if defined(_MSC_VER) && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. - // - // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. - // Users of prior VC versions shall suffer the agony and pain of - // clicking through the countless debug dialogs. - // TODO(vladl@google.com): find a way to suppress the abort dialog() in the - // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif + + // In debug mode, the Windows CRT can crash with an assertion over invalid + // input (e.g. passing an invalid file descriptor). The default handling + // for these assertions is to pop up a dialog and wait for user input. + // Instead ask the CRT to dump such assertions to stderr non-interactively. + if (!IsDebuggerPresent()) { + (void)_CrtSetReportMode(_CRT_ASSERT, + _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + } } -#endif // GTEST_HAS_SEH +#endif // GTEST_OS_WINDOWS return internal::HandleExceptionsInMethodIfSupported( impl(), @@ -3936,13 +4938,22 @@ const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } -// Returns the TestCase object for the test that's currently running, +// Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. +const TestSuite* UnitTest::current_test_suite() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_suite(); +} + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* UnitTest::current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); - return impl_->current_test_case(); + return impl_->current_test_suite(); } +#endif // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. @@ -3955,15 +4966,12 @@ const TestInfo* UnitTest::current_test_info() const // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } -#if GTEST_HAS_PARAM_TEST -// Returns ParameterizedTestCaseRegistry object used to keep track of +// Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. -internal::ParameterizedTestCaseRegistry& - UnitTest::parameterized_test_registry() - GTEST_LOCK_EXCLUDED_(mutex_) { +internal::ParameterizedTestSuiteRegistry& +UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } -#endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { @@ -3994,33 +5002,23 @@ namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4355) // Temporarily disables warning 4355 - // (using this in initializer). - default_global_test_part_result_reporter_(this), + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) + default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), -# pragma warning(pop) // Restores the warning state again. -#else - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -#endif // _MSC_VER - global_test_part_result_repoter_( + GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), -#if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), -#endif // GTEST_HAS_PARAM_TEST - last_death_test_case_(-1), - current_test_case_(NULL), - current_test_info_(NULL), + last_death_test_suite_(-1), + current_test_suite_(nullptr), + current_test_info_(nullptr), ad_hoc_test_result_(), - os_stack_trace_getter_(NULL), + os_stack_trace_getter_(nullptr), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. - random_(0), // Will be reseeded before first use. + random_(0), // Will be reseeded before first use. start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST @@ -4032,8 +5030,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) } UnitTestImpl::~UnitTestImpl() { - // Deletes every TestCase. - ForEach(test_cases_, internal::Delete); + // Deletes every TestSuite. + ForEach(test_suites_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); @@ -4042,20 +5040,20 @@ UnitTestImpl::~UnitTestImpl() { } // Adds a TestProperty to the current TestResult object when invoked in a -// context of a test, to current test case's ad_hoc_test_result when invoke -// from SetUpTestCase/TearDownTestCase, or to the global property set +// context of a test, to current test suite's ad_hoc_test_result when invoke +// from SetUpTestSuite/TearDownTestSuite, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. void UnitTestImpl::RecordProperty(const TestProperty& test_property) { std::string xml_element; TestResult* test_result; // TestResult appropriate for property recording. - if (current_test_info_ != NULL) { + if (current_test_info_ != nullptr) { xml_element = "testcase"; test_result = &(current_test_info_->result_); - } else if (current_test_case_ != NULL) { + } else if (current_test_suite_ != nullptr) { xml_element = "testsuite"; - test_result = &(current_test_case_->ad_hoc_test_result_); + test_result = &(current_test_suite_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; @@ -4067,7 +5065,7 @@ void UnitTestImpl::RecordProperty(const TestProperty& test_property) { // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { - if (internal_run_death_test_flag_.get() != NULL) + if (internal_run_death_test_flag_.get() != nullptr) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST @@ -4079,10 +5077,12 @@ void UnitTestImpl::ConfigureXmlOutput() { if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format == "json") { + listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \"" + << output_format << "\" ignored."; } } @@ -4097,9 +5097,8 @@ void UnitTestImpl::ConfigureStreamingOutput() { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { - printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", - target.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target + << "\" ignored."; } } } @@ -4115,6 +5114,11 @@ void UnitTestImpl::PostFlagParsingInit() { if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; +#if defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + // Register to send notifications about key process state changes. + listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_()); +#endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); @@ -4133,77 +5137,83 @@ void UnitTestImpl::PostFlagParsingInit() { // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ + +#if GTEST_HAS_ABSL + if (GTEST_FLAG(install_failure_signal_handler)) { + absl::FailureSignalHandlerOptions options; + absl::InstallFailureSignalHandler(options); + } +#endif // GTEST_HAS_ABSL } } -// A predicate that checks the name of a TestCase against a known +// A predicate that checks the name of a TestSuite against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // -// TestCaseNameIs is copyable. -class TestCaseNameIs { +// TestSuiteNameIs is copyable. +class TestSuiteNameIs { public: // Constructor. - explicit TestCaseNameIs(const std::string& name) - : name_(name) {} + explicit TestSuiteNameIs(const std::string& name) : name_(name) {} - // Returns true iff the name of test_case matches name_. - bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + // Returns true if and only if the name of test_suite matches name_. + bool operator()(const TestSuite* test_suite) const { + return test_suite != nullptr && + strcmp(test_suite->name(), name_.c_str()) == 0; } private: std::string name_; }; -// Finds and returns a TestCase with the given name. If one doesn't +// Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // -// test_case_name: name of the test case -// type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) { - // Can we find a TestCase with the given name? - const std::vector::const_iterator test_case = - std::find_if(test_cases_.begin(), test_cases_.end(), - TestCaseNameIs(test_case_name)); - - if (test_case != test_cases_.end()) - return *test_case; +// test_suite_name: name of the test suite +// type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite* UnitTestImpl::GetTestSuite( + const char* test_suite_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + // Can we find a TestSuite with the given name? + const auto test_suite = + std::find_if(test_suites_.rbegin(), test_suites_.rend(), + TestSuiteNameIs(test_suite_name)); + + if (test_suite != test_suites_.rend()) return *test_suite; // No. Let's create one. - TestCase* const new_test_case = - new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); - - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(test_case_name, - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. This only works when the test cases haven't + auto* const new_test_suite = + new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test suite? + if (internal::UnitTestOptions::MatchesFilter(test_suite_name, + kDeathTestSuiteFilter)) { + // Yes. Inserts the test suite after the last death test suite + // defined so far. This only works when the test suites haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. - ++last_death_test_case_; - test_cases_.insert(test_cases_.begin() + last_death_test_case_, - new_test_case); + ++last_death_test_suite_; + test_suites_.insert(test_suites_.begin() + last_death_test_suite_, + new_test_suite); } else { // No. Appends to the end of the list. - test_cases_.push_back(new_test_case); + test_suites_.push_back(new_test_suite); } - test_case_indices_.push_back(static_cast(test_case_indices_.size())); - return new_test_case; + test_suite_indices_.push_back(static_cast(test_suite_indices_.size())); + return new_test_suite; } // Helpers for setting up / tearing down the given environment. They @@ -4221,13 +5231,9 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); } // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { - // Makes sure InitGoogleTest() was called. - if (!GTestIsInitialized()) { - printf("%s", - "\nThis test program did NOT call ::testing::InitGoogleTest " - "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return false; - } + // True if and only if Google Test is initialized before RUN_ALL_TESTS() is + // called. + const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized(); // Do not run any test if the --help flag was specified. if (g_help_flag) @@ -4242,12 +5248,18 @@ bool UnitTestImpl::RunAllTests() { // protocol. internal::WriteToShardStatusFileIfNeeded(); - // True iff we are in a subprocess for running a thread-safe-style + // True if and only if we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST - in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); + in_subprocess_for_death_test = + (internal_run_death_test_flag_.get() != nullptr); +# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) + if (in_subprocess_for_death_test) { + GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_(); + } +# endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, @@ -4269,7 +5281,7 @@ bool UnitTestImpl::RunAllTests() { random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; - // True iff at least one test has failed. + // True if and only if at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); @@ -4281,17 +5293,17 @@ bool UnitTestImpl::RunAllTests() { // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. - const bool forever = repeat < 0; - for (int i = 0; forever || i != repeat; i++) { + const bool gtest_repeat_forever = repeat < 0; + for (int i = 0; gtest_repeat_forever || i != repeat; i++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); - // Shuffles test cases and tests if requested. + // Shuffles test suites and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { - random()->Reseed(random_seed_); + random()->Reseed(static_cast(random_seed_)); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. @@ -4301,19 +5313,33 @@ bool UnitTestImpl::RunAllTests() { // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); - // Runs each test case if there is at least one test to run. + // Runs each test suite if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); - // Runs the tests only if there was no fatal failure during global - // set-up. - if (!Test::HasFatalFailure()) { - for (int test_index = 0; test_index < total_test_case_count(); + // Runs the tests only if there was no fatal failure or skip triggered + // during global set-up. + if (Test::IsSkipped()) { + // Emit diagnostics when global set-up calls skip, as it will not be + // emitted by default. + TestResult& test_result = + *internal::GetUnitTestImpl()->current_test_result(); + for (int j = 0; j < test_result.total_part_count(); ++j) { + const TestPartResult& test_part_result = + test_result.GetTestPartResult(j); + if (test_part_result.type() == TestPartResult::kSkip) { + const std::string& result = test_part_result.message(); + printf("%s\n", result.c_str()); + } + } + fflush(stdout); + } else if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_suite_count(); test_index++) { - GetMutableTestCase(test_index)->Run(); + GetMutableSuiteCase(test_index)->Run(); } } @@ -4350,6 +5376,20 @@ bool UnitTestImpl::RunAllTests() { repeater->OnTestProgramEnd(*parent_); + if (!gtest_is_initialized_before_run_all_tests) { + ColoredPrintf( + COLOR_RED, + "\nIMPORTANT NOTICE - DO NOT IGNORE:\n" + "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_ + "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_ + " will start to enforce the valid usage. " + "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT +#if GTEST_FOR_GOOGLE_ + ColoredPrintf(COLOR_RED, + "For more details, see http://wiki/Main/ValidGUnitMain.\n"); +#endif // GTEST_FOR_GOOGLE_ + } + return !failed; } @@ -4359,9 +5399,9 @@ bool UnitTestImpl::RunAllTests() { // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); - if (test_shard_file != NULL) { + if (test_shard_file != nullptr) { FILE* const file = posix::FOpen(test_shard_file, "w"); - if (file == NULL) { + if (file == nullptr) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", @@ -4396,7 +5436,7 @@ bool ShouldShard(const char* total_shards_env, << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { @@ -4404,7 +5444,7 @@ bool ShouldShard(const char* total_shards_env, << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { @@ -4413,7 +5453,7 @@ bool ShouldShard(const char* total_shards_env, << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } @@ -4426,7 +5466,7 @@ bool ShouldShard(const char* total_shards_env, // and aborts. Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { const char* str_val = posix::GetEnv(var); - if (str_val == NULL) { + if (str_val == nullptr) { return default_val; } @@ -4439,8 +5479,8 @@ Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { } // Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; @@ -4448,11 +5488,11 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in -// each TestCase and TestInfo object. +// each TestSuite and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see -// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. -// Returns the number of tests that should run. +// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md +// . Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; @@ -4465,42 +5505,40 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; - for (size_t i = 0; i < test_cases_.size(); i++) { - TestCase* const test_case = test_cases_[i]; - const std::string &test_case_name = test_case->name(); - test_case->set_should_run(false); + for (auto* test_suite : test_suites_) { + const std::string& test_suite_name = test_suite->name(); + test_suite->set_should_run(false); - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - TestInfo* const test_info = test_case->test_info_list()[j]; + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + TestInfo* const test_info = test_suite->test_info_list()[j]; const std::string test_name(test_info->name()); - // A test is disabled if test case name or test name matches + // A test is disabled if test suite name or test name matches // kDisableTestFilter. - const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); + const bool is_disabled = internal::UnitTestOptions::MatchesFilter( + test_suite_name, kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter( + test_name, kDisableTestFilter); test_info->is_disabled_ = is_disabled; - const bool matches_filter = - internal::UnitTestOptions::FilterMatchesTest(test_case_name, - test_name); + const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest( + test_suite_name, test_name); test_info->matches_filter_ = matches_filter; const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; - const bool is_selected = is_runnable && - (shard_tests == IGNORE_SHARDING_PROTOCOL || - ShouldRunTestOnShard(total_shards, shard_index, - num_runnable_tests)); + const bool is_in_another_shard = + shard_tests != IGNORE_SHARDING_PROTOCOL && + !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests); + test_info->is_in_another_shard_ = is_in_another_shard; + const bool is_selected = is_runnable && !is_in_another_shard; num_runnable_tests += is_runnable; num_selected_tests += is_selected; test_info->should_run_ = is_selected; - test_case->set_should_run(test_case->should_run() || is_selected); + test_suite->set_should_run(test_suite->should_run() || is_selected); } } return num_selected_tests; @@ -4511,7 +5549,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // max_length characters, only prints the first max_length characters // and "...". static void PrintOnOneLine(const char* str, int max_length) { - if (str != NULL) { + if (str != nullptr) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); @@ -4533,27 +5571,25 @@ void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; - for (size_t i = 0; i < test_cases_.size(); i++) { - const TestCase* const test_case = test_cases_[i]; - bool printed_test_case_name = false; + for (auto* test_suite : test_suites_) { + bool printed_test_suite_name = false; - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - const TestInfo* const test_info = - test_case->test_info_list()[j]; + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + const TestInfo* const test_info = test_suite->test_info_list()[j]; if (test_info->matches_filter_) { - if (!printed_test_case_name) { - printed_test_case_name = true; - printf("%s.", test_case->name()); - if (test_case->type_param() != NULL) { + if (!printed_test_suite_name) { + printed_test_suite_name = true; + printf("%s.", test_suite->name()); + if (test_suite->type_param() != nullptr) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. - PrintOnOneLine(test_case->type_param(), kMaxParamLength); + PrintOnOneLine(test_suite->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); - if (test_info->value_param() != NULL) { + if (test_info->value_param() != nullptr) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. @@ -4564,6 +5600,23 @@ void UnitTestImpl::ListTestsMatchingFilter() { } } fflush(stdout); + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml" || output_format == "json") { + FILE* fileout = OpenFileForWriting( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); + std::stringstream stream; + if (output_format == "xml") { + XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintXmlTestsList(&stream, test_suites_); + } else if (output_format == "json") { + JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintJsonTestList(&stream, test_suites_); + } + fprintf(fileout, "%s", StringStreamToString(&stream).c_str()); + fclose(fileout); + } } // Sets the OS stack trace getter. @@ -4583,43 +5636,51 @@ void UnitTestImpl::set_os_stack_trace_getter( // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { - if (os_stack_trace_getter_ == NULL) { + if (os_stack_trace_getter_ == nullptr) { +#ifdef GTEST_OS_STACK_TRACE_GETTER_ + os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_; +#else os_stack_trace_getter_ = new OsStackTraceGetter; +#endif // GTEST_OS_STACK_TRACE_GETTER_ } return os_stack_trace_getter_; } -// Returns the TestResult for the test that's currently running, or -// the TestResult for the ad hoc test if no test is running. +// Returns the most specific TestResult currently running. TestResult* UnitTestImpl::current_test_result() { - return current_test_info_ ? - &(current_test_info_->result_) : &ad_hoc_test_result_; + if (current_test_info_ != nullptr) { + return ¤t_test_info_->result_; + } + if (current_test_suite_ != nullptr) { + return ¤t_test_suite_->ad_hoc_test_result_; + } + return &ad_hoc_test_result_; } -// Shuffles all test cases, and the tests within each test case, +// Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { - // Shuffles the death test cases. - ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + // Shuffles the death test suites. + ShuffleRange(random(), 0, last_death_test_suite_ + 1, &test_suite_indices_); - // Shuffles the non-death test cases. - ShuffleRange(random(), last_death_test_case_ + 1, - static_cast(test_cases_.size()), &test_case_indices_); + // Shuffles the non-death test suites. + ShuffleRange(random(), last_death_test_suite_ + 1, + static_cast(test_suites_.size()), &test_suite_indices_); - // Shuffles the tests inside each test case. - for (size_t i = 0; i < test_cases_.size(); i++) { - test_cases_[i]->ShuffleTests(random()); + // Shuffles the tests inside each test suite. + for (auto& test_suite : test_suites_) { + test_suite->ShuffleTests(random()); } } -// Restores the test cases and tests to their order before the first shuffle. +// Restores the test suites and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { - for (size_t i = 0; i < test_cases_.size(); i++) { - // Unshuffles the tests in each test case. - test_cases_[i]->UnshuffleTests(); - // Resets the index of each test case. - test_case_indices_[i] = static_cast(i); + for (size_t i = 0; i < test_suites_.size(); i++) { + // Unshuffles the tests in each test suite. + test_suites_[i]->UnshuffleTests(); + // Resets the index of each test suite. + test_suite_indices_[i] = static_cast(i); } } @@ -4675,16 +5736,15 @@ bool SkipPrefix(const char* prefix, const char** pstr) { // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. -const char* ParseFlagValue(const char* str, - const char* flag, - bool def_optional) { +static const char* ParseFlagValue(const char* str, const char* flag, + bool def_optional) { // str and flag must not be NULL. - if (str == NULL || flag == NULL) return NULL; + if (str == nullptr || flag == nullptr) return nullptr; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); - if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; // Skips the flag name. const char* flag_end = str + flag_len; @@ -4697,7 +5757,7 @@ const char* ParseFlagValue(const char* str, // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. - if (flag_end[0] != '=') return NULL; + if (flag_end[0] != '=') return nullptr; // Returns the string after "=". return flag_end + 1; @@ -4713,12 +5773,12 @@ const char* ParseFlagValue(const char* str, // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseBoolFlag(const char* str, const char* flag, bool* value) { +static bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); @@ -4735,7 +5795,7 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, @@ -4747,12 +5807,13 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseStringFlag(const char* str, const char* flag, std::string* value) { +template +static bool ParseStringFlag(const char* str, const char* flag, String* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Sets *value to the value of the flag. *value = value_str; @@ -4783,8 +5844,6 @@ static bool HasGoogleTestFlagPrefix(const char* str) { // @Y changes the color to yellow. // @D changes to the default terminal text color. // -// TODO(wan@google.com): Write tests for this once we add stdout -// capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. @@ -4794,7 +5853,7 @@ static void PrintColorEncoded(const char* str) { // next segment. for (;;) { const char* p = strchr(str, '@'); - if (p == NULL) { + if (p == nullptr) { ColoredPrintf(color, "%s", str); return; } @@ -4849,24 +5908,25 @@ static const char kColorEncodedHelpMessage[] = " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" +" @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate an XML report in the given directory or with the given file\n" -" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -#if GTEST_CAN_STREAM_RESULTS_ +" Generate a JSON or XML report in the given directory or with the given\n" +" file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n" +# if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" -#endif // GTEST_CAN_STREAM_RESULTS_ +# endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" -#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" -#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions.\n" +" Turn assertion failures into C++ exceptions for use by an external\n" +" test framework.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" @@ -4883,6 +5943,56 @@ static const char kColorEncodedHelpMessage[] = "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; +static bool ParseGoogleTestFlag(const char* const arg) { + return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)); +} + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +static void LoadFlagsFromFile(const std::string& path) { + FILE* flagfile = posix::FOpen(path.c_str(), "r"); + if (!flagfile) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile) + << "\""; + } + std::string contents(ReadEntireFile(flagfile)); + posix::FClose(flagfile); + std::vector lines; + SplitString(contents, '\n', &lines); + for (size_t i = 0; i < lines.size(); ++i) { + if (lines[i].empty()) + continue; + if (!ParseGoogleTestFlag(lines[i].c_str())) + g_help_flag = true; + } +} +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. @@ -4896,35 +6006,24 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { using internal::ParseInt32Flag; using internal::ParseStringFlag; - // Do we see a Google Test flag? - if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, - >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseStringFlag(arg, kStreamResultToFlag, - >EST_FLAG(stream_result_to)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, - >EST_FLAG(throw_on_failure)) - ) { - // Yes. Shift the remainder of the argv list left by one. Note + bool remove_flag = false; + if (ParseGoogleTestFlag(arg)) { + remove_flag = true; +#if GTEST_USE_OWN_FLAGFILE_FLAG_ + } else if (ParseStringFlag(arg, kFlagfileFlag, >EST_FLAG(flagfile))) { + LoadFlagsFromFile(GTEST_FLAG(flagfile)); + remove_flag = true; +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + + if (remove_flag) { + // Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. @@ -4938,12 +6037,6 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // We also need to decrement the iterator as we just removed // an element. i--; - } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?" || - HasGoogleTestFlagPrefix(arg)) { - // Both help flag and unrecognized Google Test flags (excluding - // internal ones) trigger help display. - g_help_flag = true; } } @@ -4959,6 +6052,17 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); + + // Fix the value of *_NSGetArgc() on macOS, but if and only if + // *_NSGetArgv() == argv + // Only applicable to char** version of argv +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS + if (*_NSGetArgv() == argv) { + *_NSGetArgc() = *argc; + } +#endif +#endif } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); @@ -4970,23 +6074,19 @@ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { - g_init_gtest_count++; - // We don't want to run the initialization code twice. - if (g_init_gtest_count != 1) return; + if (GTestIsInitialized()) return; if (*argc <= 0) return; - internal::g_executable_path = internal::StreamableToString(argv[0]); - -#if GTEST_HAS_DEATH_TEST - g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } -#endif // GTEST_HAS_DEATH_TEST +#if GTEST_HAS_ABSL + absl::InitializeSymbolizer(g_argvs[0].c_str()); +#endif // GTEST_HAS_ABSL ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); @@ -5004,13 +6104,78 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +void InitGoogleTest() { + // Since Arduino doesn't have a command line, fake out the argc/argv arguments + int argc = 1; + const auto arg0 = "dummy"; + char* argv0 = const_cast(arg0); + char** argv = &argv0; + +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(&argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + internal::InitGoogleTestImpl(&argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + +std::string TempDir() { +#if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) + return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + return "\\temp\\"; +#elif GTEST_OS_WINDOWS + const char* temp_dir = internal::posix::GetEnv("TEMP"); + if (temp_dir == nullptr || temp_dir[0] == '\0') + return "\\temp\\"; + else if (temp_dir[strlen(temp_dir) - 1] == '\\') + return temp_dir; + else + return std::string(temp_dir) + "\\"; +#elif GTEST_OS_LINUX_ANDROID + return "/sdcard/"; +#else + return "/tmp/"; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +void ScopedTrace::PushTrace(const char* file, int line, std::string message) { + internal::TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message.swap(message); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + UnitTest::GetInstance()->PopGTestTrace(); } } // namespace testing diff --git a/test/gtest/src/gtest_main.cc b/test/gtest/src/gtest_main.cc index 94540b128b..f6e1dd96fb 100644 --- a/test/gtest/src/gtest_main.cc +++ b/test/gtest/src/gtest_main.cc @@ -27,12 +27,21 @@ // (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 // NOLINT - +#include #include "gtest/gtest.h" -GTEST_API_ int main(int argc, char **argv) { // NOLINT - printf("Running main() from gtest_main.cc\n"); +#ifdef ARDUINO +void setup() { + testing::InitGoogleTest(); +} + +void loop() { RUN_ALL_TESTS(); } + +#else + +GTEST_API_ int main(int argc, char **argv) { + printf("Running main() from %s\n", __FILE__); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } +#endif diff --git a/test/integration/diff_drive_system.cc b/test/integration/diff_drive_system.cc index 2d4da67079..1d55d2b576 100644 --- a/test/integration/diff_drive_system.cc +++ b/test/integration/diff_drive_system.cc @@ -418,5 +418,5 @@ TEST_P(DiffDriveTest, OdomCustomFrameId) } // Run multiple times -INSTANTIATE_TEST_CASE_P(ServerRepeat, DiffDriveTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, DiffDriveTest, ::testing::Range(1, 2)); diff --git a/test/integration/examples_build.cc b/test/integration/examples_build.cc index 9c916b563e..ab1fa1a38b 100644 --- a/test/integration/examples_build.cc +++ b/test/integration/examples_build.cc @@ -174,7 +174,7 @@ TEST_P(ExamplesBuild, Build) } ////////////////////////////////////////////////// -INSTANTIATE_TEST_CASE_P(Plugins, ExamplesBuild, ::testing::Values( +INSTANTIATE_TEST_SUITE_P(Plugins, ExamplesBuild, ::testing::Values( "plugin", "standalone" )); diff --git a/test/integration/scene_broadcaster_system.cc b/test/integration/scene_broadcaster_system.cc index 8caac85336..b5ae9c0f9c 100644 --- a/test/integration/scene_broadcaster_system.cc +++ b/test/integration/scene_broadcaster_system.cc @@ -564,5 +564,5 @@ TEST_P(SceneBroadcasterTest, StateStatic) } // Run multiple times -INSTANTIATE_TEST_CASE_P(ServerRepeat, SceneBroadcasterTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, SceneBroadcasterTest, ::testing::Range(1, 2)); diff --git a/test/integration/velocity_control_system.cc b/test/integration/velocity_control_system.cc index b3f21ef9dd..02b230c844 100644 --- a/test/integration/velocity_control_system.cc +++ b/test/integration/velocity_control_system.cc @@ -146,5 +146,5 @@ TEST_P(VelocityControlTest, PublishCmd) } // Run multiple times -INSTANTIATE_TEST_CASE_P(ServerRepeat, VelocityControlTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, VelocityControlTest, ::testing::Range(1, 2)); From 80e7934dd9502810a46239bf8b8b8bc25cf53da7 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Thu, 7 Jan 2021 12:16:37 -0600 Subject: [PATCH 10/21] Apply suggestions from code review Signed-off-by: Michael Carroll Co-authored-by: Louise Poubel --- tutorials/migrating_ardupilot_plugin.md | 6 +++--- tutorials/video_recorder.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tutorials/migrating_ardupilot_plugin.md b/tutorials/migrating_ardupilot_plugin.md index b661e258b1..cb499e77f3 100644 --- a/tutorials/migrating_ardupilot_plugin.md +++ b/tutorials/migrating_ardupilot_plugin.md @@ -22,7 +22,7 @@ documentation](https://ardupilot.org/dev/docs/using-gazebo-simulator-with-sitl.h As context to understand what we're migrating, here's a system diagram for how the ArduPilot Gazebo plugin works is used: - + *UAV icon credit: By Julian Herzog, CC BY 4.0, https://commons.wikimedia.org/w/index.php?curid=60965475* @@ -224,8 +224,8 @@ To better understand the ECS pattern as it is used in Ignition, it's helpful to learn about the EntityComponentManager (ECM), which is responsible for managing the ECS graph. A great resource to understand the logic under the hood of the ECM is the `SdfEntityCreator` class -([header](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo3/include/ignition/gazebo/SdfEntityCreator.hh), -[source](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo3/src/SdfEntityCreator.cc)). +([header](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo4/include/ignition/gazebo/SdfEntityCreator.hh), +[source](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo4/src/SdfEntityCreator.cc)). This class is responsible for mapping the content of an SDF file to the entities and components that form the graph handled by the ECM. For example, if you wonder which components can be accessed by default from the plugin, this diff --git a/tutorials/video_recorder.md b/tutorials/video_recorder.md index 54b8fbe519..50bbef75d9 100644 --- a/tutorials/video_recorder.md +++ b/tutorials/video_recorder.md @@ -38,7 +38,7 @@ the [GUI Configuration](gui_config.html) tutorial for more information. If you launched Ignition Gazebo with the `video_record_dbl_pendulum.sdf` demo world, the GUI configurations are embedded in the world SDF file so you will need to download a copy of the -[sdf file](https://raw.githubusercontent.com/ignitionrobotics/ign-gazebo/ign-gazebo3/examples/worlds/video_record_dbl_pendulum.sdf). +[sdf file](https://raw.githubusercontent.com/ignitionrobotics/ign-gazebo/ign-gazebo4/examples/worlds/video_record_dbl_pendulum.sdf). and modify the GUI configuration in that file. On the other hand, if you launched Ignition Gazebo with a world file that does not have GUI configurations, you will need to specify the settings in From f05166ef184e284ba2f6ec67c6744326d621eabf Mon Sep 17 00:00:00 2001 From: Akash Patel <17132214+acxz@users.noreply.github.com> Date: Thu, 7 Jan 2021 14:01:53 -0500 Subject: [PATCH 11/21] change nullptr to a int ptr for qt 5.15.2 bug (#527) See: https://bugreports.qt.io/browse/QTBUG-89114 Signed-off-by: acxz <17132214+acxz@users.noreply.github.com> Co-authored-by: Louise Poubel Signed-off-by: Louise Poubel --- src/gui/plugins/scene3d/Scene3D.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index 8854e38de6..2e51b6f440 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -1970,8 +1970,9 @@ TextureNode::TextureNode(QQuickWindow *_window) #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) this->texture = this->window->createTextureFromId(0, QSize(1, 1)); #else + void * nativeLayout; this->texture = this->window->createTextureFromNativeObject( - QQuickWindow::NativeObjectTexture, nullptr, 0, QSize(1, 1), + QQuickWindow::NativeObjectTexture, &nativeLayout, 0, QSize(1, 1), QQuickWindow::TextureIsOpaque); #endif this->setTexture(this->texture); From d18026e8b28c3ba8e66575f05f444f3d9c51c506 Mon Sep 17 00:00:00 2001 From: Louise Poubel Date: Thu, 7 Jan 2021 12:39:27 -0800 Subject: [PATCH 12/21] Generate valid topics everywhere (support names with spaces) (#522) Signed-off-by: Louise Poubel --- CMakeLists.txt | 2 +- examples/worlds/spaces.sdf | 108 ++++++++++++++++++ include/ignition/gazebo/Util.hh | 15 +++ src/LevelManager.cc | 10 +- src/SimulationRunner.cc | 13 ++- src/Util.cc | 22 ++++ src/Util_TEST.cc | 47 +++++++- src/gui/Gui.cc | 33 ++++-- src/gui/GuiRunner.cc | 18 ++- src/gui/plugins/scene3d/Scene3D.cc | 17 +++ .../apply_joint_force/ApplyJointForce.cc | 12 +- .../battery_plugin/LinearBatteryPlugin.cc | 31 ++++- src/systems/breadcrumbs/Breadcrumbs.cc | 13 ++- .../CameraVideoRecorder.cc | 29 ++++- .../detachable_joint/DetachableJoint.cc | 16 ++- src/systems/diff_drive/DiffDrive.cc | 21 +++- .../joint_controller/JointController.cc | 11 +- .../JointPositionController.cc | 12 +- src/systems/log/LogRecord.cc | 24 +++- .../LogicalAudioSensorPlugin.cc | 13 ++- .../MulticopterVelocityControl.cc | 25 +++- .../MulticopterMotorModel.cc | 10 +- .../scene_broadcaster/SceneBroadcaster.cc | 16 ++- src/systems/touch_plugin/TouchPlugin.cc | 9 +- .../triggered_publisher/TriggeredPublisher.cc | 10 +- src/systems/user_commands/UserCommands.cc | 18 ++- .../velocity_control/VelocityControl.cc | 10 +- src/systems/wind_effects/WindEffects.cc | 12 +- 28 files changed, 498 insertions(+), 79 deletions(-) create mode 100644 examples/worlds/spaces.sdf diff --git a/CMakeLists.txt b/CMakeLists.txt index ce24763e77..4d4f036811 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ set(IGN_FUEL_TOOLS_VER ${ignition-fuel_tools5_VERSION_MAJOR}) #-------------------------------------- # Find ignition-gui -ign_find_package(ignition-gui4 REQUIRED VERSION 4.1) +ign_find_package(ignition-gui4 REQUIRED VERSION 4.1.1) set(IGN_GUI_VER ${ignition-gui4_VERSION_MAJOR}) ign_find_package (Qt5 COMPONENTS diff --git a/examples/worlds/spaces.sdf b/examples/worlds/spaces.sdf new file mode 100644 index 0000000000..0109d50943 --- /dev/null +++ b/examples/worlds/spaces.sdf @@ -0,0 +1,108 @@ + + + + + + 0.001 + 1.0 + + + + + + + + + + 1.0 1.0 1.0 + 0.8 0.8 0.8 + + + + true + 0 0 10 0 0 0 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + 1000 + 0.9 + 0.01 + 0.001 + + -0.5 0.1 -0.9 + + + + true + + + + + 0 0 1 + + + + + + + 0 0 1 + 100 100 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + + + 0 0 0.5 0 0 0 + + + + 1 + 0 + 0 + 1 + 0 + 1 + + 1.0 + + + + + 1 1 1 + + + + + + + + 1 1 1 + + + + 1 0 0 1 + 1 0 0 1 + 1 0 0 1 + + + + + + diff --git a/include/ignition/gazebo/Util.hh b/include/ignition/gazebo/Util.hh index 39d790f7f9..3e9b9c8fec 100644 --- a/include/ignition/gazebo/Util.hh +++ b/include/ignition/gazebo/Util.hh @@ -139,6 +139,21 @@ namespace ignition const Entity &_entity, const EntityComponentManager &_ecm); + /// \brief Helper function to generate a valid transport topic, given + /// a list of topics ordered by preference. The generated topic will be, + /// in this order: + /// + /// 1. The first topic unchanged, if valid. + /// 2. A valid version of the first topic, if possible. + /// 3. The second topic unchanged, if valid. + /// 4. A valid version of the second topic, if possible. + /// 5. ... + /// 6. If no valid topics could be generated, return an empty string. + /// + /// \param[in] _topics Topics ordered by preference. + std::string IGNITION_GAZEBO_VISIBLE validTopic( + const std::vector &_topics); + /// \brief Environment variable holding resource paths. const std::string kResourcePathEnv{"IGN_GAZEBO_RESOURCE_PATH"}; diff --git a/src/LevelManager.cc b/src/LevelManager.cc index d3dcbec7d0..1b54f01848 100644 --- a/src/LevelManager.cc +++ b/src/LevelManager.cc @@ -76,8 +76,14 @@ LevelManager::LevelManager(SimulationRunner *_runner, const bool _useLevels) this->ReadLevelPerformerInfo(); this->CreatePerformers(); - std::string service = "/world/"; - service += this->runner->sdfWorld->Name() + "/level/set_performer"; + std::string service = transport::TopicUtils::AsValidTopic("/world/" + + this->runner->sdfWorld->Name() + "/level/set_performer"); + if (service.empty()) + { + ignerr << "Failed to generate set_performer topic for world [" + << this->runner->sdfWorld->Name() << "]" << std::endl; + return; + } this->node.Advertise(service, &LevelManager::OnSetPerformer, this); } diff --git a/src/SimulationRunner.cc b/src/SimulationRunner.cc index 9777417c33..e047ffaa39 100644 --- a/src/SimulationRunner.cc +++ b/src/SimulationRunner.cc @@ -157,15 +157,20 @@ SimulationRunner::SimulationRunner(const sdf::World *_world, // World control transport::NodeOptions opts; + std::string ns{"/world/" + this->worldName}; if (this->networkMgr) { - opts.SetNameSpace(this->networkMgr->Namespace() + - "/world/" + this->worldName); + ns = this->networkMgr->Namespace() + ns; } - else + + auto validNs = transport::TopicUtils::AsValidTopic(ns); + if (validNs.empty()) { - opts.SetNameSpace("/world/" + this->worldName); + ignerr << "Invalid namespace [" << ns + << "], not initializing runner transport." << std::endl; + return; } + opts.SetNameSpace(validNs); this->node = std::make_unique(opts); diff --git a/src/Util.cc b/src/Util.cc index 5b5995ae9e..828483d0f0 100644 --- a/src/Util.cc +++ b/src/Util.cc @@ -24,6 +24,7 @@ #endif #include #include +#include #include "ignition/gazebo/components/Actor.hh" #include "ignition/gazebo/components/Collision.hh" @@ -416,6 +417,27 @@ ignition::gazebo::Entity topLevelModel(const Entity &_entity, } return entity; } + +////////////////////////////////////////////////// +std::string validTopic(const std::vector &_topics) +{ + for (const auto &topic : _topics) + { + auto validTopic = transport::TopicUtils::AsValidTopic(topic); + if (validTopic.empty()) + { + ignerr << "Topic [" << topic << "] is invalid, ignoring." << std::endl; + continue; + } + if (validTopic != topic) + { + igndbg << "Topic [" << topic << "] changed to valid topic [" + << validTopic << "]" << std::endl; + } + return validTopic; + } + return std::string(); +} } } } diff --git a/src/Util_TEST.cc b/src/Util_TEST.cc index 501fdb5939..d699b3dc3b 100644 --- a/src/Util_TEST.cc +++ b/src/Util_TEST.cc @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -36,8 +37,18 @@ using namespace ignition; using namespace gazebo; +/// \brief Tests for Util.hh +class UtilTest : public ::testing::Test +{ + // Documentation inherited + protected: void SetUp() override + { + common::Console::SetVerbosity(4); + } +}; + ///////////////////////////////////////////////// -TEST(UtilTest, ScopedName) +TEST_F(UtilTest, ScopedName) { EntityComponentManager ecm; @@ -219,7 +230,7 @@ TEST(UtilTest, ScopedName) } ///////////////////////////////////////////////// -TEST(UtilTest, EntityTypeId) +TEST_F(UtilTest, EntityTypeId) { EntityComponentManager ecm; @@ -264,7 +275,7 @@ TEST(UtilTest, EntityTypeId) } ///////////////////////////////////////////////// -TEST(UtilTest, EntityTypeStr) +TEST_F(UtilTest, EntityTypeStr) { EntityComponentManager ecm; @@ -309,7 +320,7 @@ TEST(UtilTest, EntityTypeStr) } ///////////////////////////////////////////////// -TEST(UtilTest, RemoveParentScopedName) +TEST_F(UtilTest, RemoveParentScopedName) { EXPECT_EQ(removeParentScope("world/world_name", "/"), "world_name"); EXPECT_EQ(removeParentScope("world::world_name::light::lightA_name", "::"), @@ -324,7 +335,7 @@ TEST(UtilTest, RemoveParentScopedName) } ///////////////////////////////////////////////// -TEST(UtilTest, AsFullPath) +TEST_F(UtilTest, AsFullPath) { const std::string relativeUriUnix{"meshes/collision.dae"}; const std::string relativeUriWindows{"meshes\\collision.dae"}; @@ -408,7 +419,7 @@ TEST(UtilTest, AsFullPath) } ///////////////////////////////////////////////// -TEST(UtilTest, TopLevelModel) +TEST_F(UtilTest, TopLevelModel) { EntityComponentManager ecm; @@ -463,3 +474,27 @@ TEST(UtilTest, TopLevelModel) // model C should have itself as the top level entity EXPECT_EQ(modelCEntity, topLevelModel(modelCEntity, ecm)); } + +///////////////////////////////////////////////// +TEST_F(UtilTest, ValidTopic) +{ + std::string good{"good"}; + std::string fixable{"not bad~"}; + std::string invalid{"@~@~@~"}; + + EXPECT_EQ("good", validTopic({good})); + EXPECT_EQ("not_bad", validTopic({fixable})); + EXPECT_EQ("", validTopic({invalid})); + + EXPECT_EQ("good", validTopic({good, fixable})); + EXPECT_EQ("not_bad", validTopic({fixable, good})); + + EXPECT_EQ("good", validTopic({good, invalid})); + EXPECT_EQ("good", validTopic({invalid, good})); + + EXPECT_EQ("not_bad", validTopic({fixable, invalid})); + EXPECT_EQ("not_bad", validTopic({invalid, fixable})); + + EXPECT_EQ("not_bad", validTopic({fixable, invalid, good})); + EXPECT_EQ("good", validTopic({invalid, good, fixable})); +} diff --git a/src/gui/Gui.cc b/src/gui/Gui.cc index b375e912fe..1c4912a6d2 100644 --- a/src/gui/Gui.cc +++ b/src/gui/Gui.cc @@ -194,18 +194,31 @@ std::unique_ptr createGui( // Request GUI info for each world result = false; - service = std::string("/world/" + worldName + "/gui/info"); - - igndbg << "Requesting GUI from [" << service << "]..." << std::endl; - - // Request and block ignition::msgs::GUI res; - executed = node.Request(service, timeout, res, result); + service = transport::TopicUtils::AsValidTopic("/world/" + worldName + + "/gui/info"); + if (service.empty()) + { + ignerr << "Failed to generate valid service for world [" << worldName + << "]" << std::endl; + } + else + { + igndbg << "Requesting GUI from [" << service << "]..." << std::endl; - if (!executed) - ignerr << "Service call timed out for [" << service << "]" << std::endl; - else if (!result) - ignerr << "Service call failed for [" << service << "]" << std::endl; + // Request and block + executed = node.Request(service, timeout, res, result); + + if (!executed) + { + ignerr << "Service call timed out for [" << service << "]" + << std::endl; + } + else if (!result) + { + ignerr << "Service call failed for [" << service << "]" << std::endl; + } + } // GUI runner auto runner = new ignition::gazebo::GuiRunner(worldName); diff --git a/src/gui/GuiRunner.cc b/src/gui/GuiRunner.cc index 565838a06c..6f88a441fe 100644 --- a/src/gui/GuiRunner.cc +++ b/src/gui/GuiRunner.cc @@ -40,7 +40,14 @@ GuiRunner::GuiRunner(const std::string &_worldName) winWorldNames.append(QString::fromStdString(_worldName)); win->setProperty("worldNames", winWorldNames); - this->stateTopic = "/world/" + _worldName + "/state"; + this->stateTopic = transport::TopicUtils::AsValidTopic("/world/" + + _worldName + "/state"); + if (this->stateTopic.empty()) + { + ignerr << "Failed to generate valid topic for world [" << _worldName << "]" + << std::endl; + return; + } common::addFindFileURICallback([] (common::URI _uri) { @@ -63,6 +70,15 @@ void GuiRunner::RequestState() std::string id = std::to_string(gui::App()->applicationPid()); std::string reqSrv = this->node.Options().NameSpace() + "/" + id + "/state_async"; + auto reqSrvValid = transport::TopicUtils::AsValidTopic(reqSrv); + if (reqSrvValid.empty()) + { + ignerr << "Failed to generate valid service [" << reqSrv << "]" + << std::endl; + return; + } + reqSrv = reqSrvValid; + this->node.Advertise(reqSrv, &GuiRunner::OnStateAsyncService, this); ignition::msgs::StringMsg req; req.set_data(reqSrv); diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index 2e51b6f440..a91f4821c4 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -1029,6 +1029,15 @@ void IgnRenderer::HandleModelPlacement() this->dataPtr->createCmdService = "/world/" + this->worldName + "/create"; } + this->dataPtr->createCmdService = transport::TopicUtils::AsValidTopic( + this->dataPtr->createCmdService); + if (this->dataPtr->createCmdService.empty()) + { + ignerr << "Failed to create valid create command service for world [" + << this->worldName <<"]" << std::endl; + return; + } + this->dataPtr->node.Request(this->dataPtr->createCmdService, req, cb); this->dataPtr->isPlacing = false; this->dataPtr->mouseDirty = false; @@ -1247,6 +1256,14 @@ void IgnRenderer::HandleMouseTransformControl() this->dataPtr->poseCmdService = "/world/" + this->worldName + "/set_pose"; } + this->dataPtr->poseCmdService = transport::TopicUtils::AsValidTopic( + this->dataPtr->poseCmdService); + if (this->dataPtr->poseCmdService.empty()) + { + ignerr << "Failed to create valid pose command service for world [" + << this->worldName <<"]" << std::endl; + return; + } this->dataPtr->node.Request(this->dataPtr->poseCmdService, req, cb); } diff --git a/src/systems/apply_joint_force/ApplyJointForce.cc b/src/systems/apply_joint_force/ApplyJointForce.cc index 582d46e101..042f585565 100644 --- a/src/systems/apply_joint_force/ApplyJointForce.cc +++ b/src/systems/apply_joint_force/ApplyJointForce.cc @@ -25,6 +25,7 @@ #include "ignition/gazebo/components/JointForceCmd.hh" #include "ignition/gazebo/Model.hh" +#include "ignition/gazebo/Util.hh" using namespace ignition; using namespace gazebo; @@ -93,8 +94,15 @@ void ApplyJointForce::Configure(const Entity &_entity, } // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + "/joint/" + - this->dataPtr->jointName + "/cmd_force"}; + auto topic = transport::TopicUtils::AsValidTopic("/model/" + + this->dataPtr->model.Name(_ecm) + "/joint/" + this->dataPtr->jointName + + "/cmd_force"); + if (topic.empty()) + { + ignerr << "Failed to create valid topic for [" << this->dataPtr->jointName + << "]" << std::endl; + return; + } this->dataPtr->node.Subscribe(topic, &ApplyJointForcePrivate::OnCmdForce, this->dataPtr.get()); diff --git a/src/systems/battery_plugin/LinearBatteryPlugin.cc b/src/systems/battery_plugin/LinearBatteryPlugin.cc index 47530eff67..8c8f94b32d 100644 --- a/src/systems/battery_plugin/LinearBatteryPlugin.cc +++ b/src/systems/battery_plugin/LinearBatteryPlugin.cc @@ -297,16 +297,28 @@ void LinearBatteryPlugin::Configure(const Entity &_entity, "/battery/" + _sdf->Get("battery_name") + "/recharge/stop"; - this->dataPtr->node.Advertise(enableRechargeTopic, + auto validEnableRechargeTopic = transport::TopicUtils::AsValidTopic( + enableRechargeTopic); + auto validDisableRechargeTopic = transport::TopicUtils::AsValidTopic( + disableRechargeTopic); + if (validEnableRechargeTopic.empty() || validDisableRechargeTopic.empty()) + { + ignerr << "Failed to create valid topics. Not valid: [" + << enableRechargeTopic << "] and [" << disableRechargeTopic + << "]" << std::endl; + return; + } + + this->dataPtr->node.Advertise(validEnableRechargeTopic, &LinearBatteryPluginPrivate::OnEnableRecharge, this->dataPtr.get()); - this->dataPtr->node.Advertise(disableRechargeTopic, + this->dataPtr->node.Advertise(validDisableRechargeTopic, &LinearBatteryPluginPrivate::OnDisableRecharge, this->dataPtr.get()); if (_sdf->HasElement("recharge_by_topic")) { - this->dataPtr->node.Subscribe(enableRechargeTopic, + this->dataPtr->node.Subscribe(validEnableRechargeTopic, &LinearBatteryPluginPrivate::OnEnableRecharge, this->dataPtr.get()); - this->dataPtr->node.Subscribe(disableRechargeTopic, + this->dataPtr->node.Subscribe(validDisableRechargeTopic, &LinearBatteryPluginPrivate::OnDisableRecharge, this->dataPtr.get()); } } @@ -338,10 +350,19 @@ void LinearBatteryPlugin::Configure(const Entity &_entity, // Setup battery state topic std::string stateTopic{"/model/" + this->dataPtr->model.Name(_ecm) + "/battery/" + this->dataPtr->battery->Name() + "/state"}; + + auto validStateTopic = transport::TopicUtils::AsValidTopic(stateTopic); + if (validStateTopic.empty()) + { + ignerr << "Failed to create valid state topic [" + << stateTopic << "]" << std::endl; + return; + } + transport::AdvertiseMessageOptions opts; opts.SetMsgsPerSec(50); this->dataPtr->statePub = this->dataPtr->node.Advertise( - stateTopic, opts); + validStateTopic, opts); } ///////////////////////////////////////////////// diff --git a/src/systems/breadcrumbs/Breadcrumbs.cc b/src/systems/breadcrumbs/Breadcrumbs.cc index a06789d845..ba98482007 100644 --- a/src/systems/breadcrumbs/Breadcrumbs.cc +++ b/src/systems/breadcrumbs/Breadcrumbs.cc @@ -42,6 +42,7 @@ #include "ignition/gazebo/components/Performer.hh" #include "ignition/gazebo/components/Pose.hh" #include "ignition/gazebo/components/World.hh" +#include "ignition/gazebo/Util.hh" using namespace ignition; using namespace gazebo; @@ -132,11 +133,15 @@ void Breadcrumbs::Configure(const Entity &_entity, } // Subscribe to commands - std::string topic{"/model/" + this->model.Name(_ecm) + "/breadcrumbs/" + - this->modelRoot.ModelByIndex(0)->Name() + "/deploy"}; - + std::vector topics; if (_sdf->HasElement("topic")) - topic = _sdf->Get("topic"); + { + topics.push_back(_sdf->Get("topic")); + } + topics.push_back("/model/" + + this->model.Name(_ecm) + "/breadcrumbs/" + + this->modelRoot.ModelByIndex(0)->Name() + "/deploy"); + auto topic = validTopic(topics); this->node.Subscribe(topic, &Breadcrumbs::OnDeploy, this); this->remainingPub = this->node.Advertise(topic + "/remaining"); diff --git a/src/systems/camera_video_recorder/CameraVideoRecorder.cc b/src/systems/camera_video_recorder/CameraVideoRecorder.cc index 52c24ad0f9..cadc7b4b3d 100644 --- a/src/systems/camera_video_recorder/CameraVideoRecorder.cc +++ b/src/systems/camera_video_recorder/CameraVideoRecorder.cc @@ -200,7 +200,13 @@ void CameraVideoRecorder::Configure( // video recorder service topic name if (_sdf->HasElement("service")) { - this->dataPtr->service = _sdf->Get("service"); + this->dataPtr->service = transport::TopicUtils::AsValidTopic( + _sdf->Get("service")); + if (this->dataPtr->service.empty()) + { + ignerr << "Service [" << _sdf->Get("service") + << "] not valid. Ignoring." << std::endl; + } } this->dataPtr->eventMgr = &_eventMgr; @@ -208,7 +214,15 @@ void CameraVideoRecorder::Configure( sdf::Sensor sensorSdf = cameraEntComp->Data(); std::string topic = sensorSdf.Topic(); if (topic.empty()) - topic = scopedName(_entity, _ecm) + "/image"; + { + auto scoped = scopedName(_entity, _ecm); + topic = transport::TopicUtils::AsValidTopic(scoped + "/image"); + if (topic.empty()) + { + ignerr << "Failed to generate valid topic for entity [" << scoped + << "]" << std::endl; + } + } this->dataPtr->sensorTopic = topic; } @@ -363,8 +377,15 @@ void CameraVideoRecorder::PostUpdate(const UpdateInfo &, if (this->dataPtr->service.empty()) { - this->dataPtr->service = scopedName(this->dataPtr->entity, _ecm) + - "/record_video"; + auto scoped = scopedName(this->dataPtr->entity, _ecm); + this->dataPtr->service = transport::TopicUtils::AsValidTopic(scoped + + "/record_video"); + if (this->dataPtr->service.empty()) + { + ignerr << "Failed to create valid service for [" << scoped << "]" + << std::endl; + } + return; } this->dataPtr->node.Advertise(this->dataPtr->service, diff --git a/src/systems/detachable_joint/DetachableJoint.cc b/src/systems/detachable_joint/DetachableJoint.cc index 1ed2125a1f..0946aa9505 100644 --- a/src/systems/detachable_joint/DetachableJoint.cc +++ b/src/systems/detachable_joint/DetachableJoint.cc @@ -15,6 +15,8 @@ * */ +#include + #include #include @@ -22,13 +24,14 @@ #include -#include "ignition/gazebo/Model.hh" #include "ignition/gazebo/components/DetachableJoint.hh" #include "ignition/gazebo/components/Link.hh" #include "ignition/gazebo/components/Model.hh" #include "ignition/gazebo/components/Name.hh" #include "ignition/gazebo/components/ParentEntity.hh" #include "ignition/gazebo/components/Pose.hh" +#include "ignition/gazebo/Model.hh" +#include "ignition/gazebo/Util.hh" #include "DetachableJoint.hh" @@ -93,9 +96,14 @@ void DetachableJoint::Configure(const Entity &_entity, } // Setup detach topic - std::string defaultTopic{"/model/" + this->model.Name(_ecm) + - "/detachable_joint/detach"}; - this->topic = _sdf->Get("topic", defaultTopic).first; + std::vector topics; + if (_sdf->HasElement("topic")) + { + topics.push_back(_sdf->Get("topic")); + } + topics.push_back("/model/" + this->model.Name(_ecm) + + "/detachable_joint/detach"); + this->topic = validTopic(topics); this->suppressChildWarning = _sdf->Get("suppress_child_warning", this->suppressChildWarning) diff --git a/src/systems/diff_drive/DiffDrive.cc b/src/systems/diff_drive/DiffDrive.cc index dfd78b7769..1686beebcd 100644 --- a/src/systems/diff_drive/DiffDrive.cc +++ b/src/systems/diff_drive/DiffDrive.cc @@ -36,6 +36,7 @@ #include "ignition/gazebo/components/JointVelocityCmd.hh" #include "ignition/gazebo/Link.hh" #include "ignition/gazebo/Model.hh" +#include "ignition/gazebo/Util.hh" #include "SpeedLimiter.hh" @@ -253,16 +254,26 @@ void DiffDrive::Configure(const Entity &_entity, this->dataPtr->wheelRadius, this->dataPtr->wheelRadius); // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + "/cmd_vel"}; + std::vector topics; if (_sdf->HasElement("topic")) - topic = _sdf->Get("topic"); + { + topics.push_back(_sdf->Get("topic")); + } + topics.push_back("/model/" + this->dataPtr->model.Name(_ecm) + "/cmd_vel"); + auto topic = validTopic(topics); + this->dataPtr->node.Subscribe(topic, &DiffDrivePrivate::OnCmdVel, this->dataPtr.get()); - std::string odomTopic{"/model/" + this->dataPtr->model.Name(_ecm) + - "/odometry"}; + std::vector odomTopics; if (_sdf->HasElement("odom_topic")) - odomTopic = _sdf->Get("odom_topic"); + { + odomTopics.push_back(_sdf->Get("odom_topic")); + } + odomTopics.push_back("/model/" + this->dataPtr->model.Name(_ecm) + + "/odometry"); + auto odomTopic = validTopic(odomTopics); + this->dataPtr->odomPub = this->dataPtr->node.Advertise( odomTopic); diff --git a/src/systems/joint_controller/JointController.cc b/src/systems/joint_controller/JointController.cc index 42990d4447..dd2f645f1d 100644 --- a/src/systems/joint_controller/JointController.cc +++ b/src/systems/joint_controller/JointController.cc @@ -131,8 +131,15 @@ void JointController::Configure(const Entity &_entity, } // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + "/joint/" + - this->dataPtr->jointName + "/cmd_vel"}; + std::string topic = transport::TopicUtils::AsValidTopic("/model/" + + this->dataPtr->model.Name(_ecm) + "/joint/" + this->dataPtr->jointName + + "/cmd_vel"); + if (topic.empty()) + { + ignerr << "Failed to create topic for joint [" << this->dataPtr->jointName + << "]" << std::endl; + return; + } this->dataPtr->node.Subscribe(topic, &JointControllerPrivate::OnCmdVel, this->dataPtr.get()); diff --git a/src/systems/joint_position_controller/JointPositionController.cc b/src/systems/joint_position_controller/JointPositionController.cc index c048ff0e23..5eaefaf45e 100644 --- a/src/systems/joint_position_controller/JointPositionController.cc +++ b/src/systems/joint_position_controller/JointPositionController.cc @@ -147,9 +147,15 @@ void JointPositionController::Configure(const Entity &_entity, this->dataPtr->posPid.Init(p, i, d, iMax, iMin, cmdMax, cmdMin, cmdOffset); // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + - "/joint/" + this->dataPtr->jointName + "/" + - std::to_string(this->dataPtr->jointIndex) + "/cmd_pos"}; + std::string topic = transport::TopicUtils::AsValidTopic("/model/" + + this->dataPtr->model.Name(_ecm) + "/joint/" + this->dataPtr->jointName + + "/" + std::to_string(this->dataPtr->jointIndex) + "/cmd_pos"); + if (topic.empty()) + { + ignerr << "Failed to create topic for joint [" << this->dataPtr->jointName + << "]" << std::endl; + return; + } this->dataPtr->node.Subscribe( topic, &JointPositionControllerPrivate::OnCmdPos, this->dataPtr.get()); diff --git a/src/systems/log/LogRecord.cc b/src/systems/log/LogRecord.cc index 233d7049a9..3febe2343a 100644 --- a/src/systems/log/LogRecord.cc +++ b/src/systems/log/LogRecord.cc @@ -291,11 +291,31 @@ bool LogRecordPrivate::Start(const std::string &_logPath, // Use directory basename as topic name, to be able to retrieve at playback std::string sdfTopic = "/" + common::basename(this->logPath) + "/sdf"; - this->sdfPub = this->node.Advertise(sdfTopic, this->sdfMsg.GetTypeName()); + auto validSdfTopic = transport::TopicUtils::AsValidTopic(sdfTopic); + if (!validSdfTopic.empty()) + { + this->sdfPub = this->node.Advertise(validSdfTopic, + this->sdfMsg.GetTypeName()); + } + else + { + ignerr << "Failed to generate valid topic to publish SDF. Tried [" + << sdfTopic << "]." << std::endl; + } // TODO(louise) Combine with SceneBroadcaster's state topic std::string stateTopic = "/world/" + this->worldName + "/changed_state"; - this->statePub = this->node.Advertise(stateTopic); + auto validStateTopic = transport::TopicUtils::AsValidTopic(stateTopic); + if (!validStateTopic.empty()) + { + this->statePub = this->node.Advertise( + validStateTopic); + } + else + { + ignerr << "Failed to generate valid topic to publish state. Tried [" + << stateTopic << "]." << std::endl; + } // Append file name std::string dbPath = common::joinPaths(this->logPath, "state.tlog"); diff --git a/src/systems/logical_audio_sensor_plugin/LogicalAudioSensorPlugin.cc b/src/systems/logical_audio_sensor_plugin/LogicalAudioSensorPlugin.cc index 33b9310b2b..78ab1b7d65 100644 --- a/src/systems/logical_audio_sensor_plugin/LogicalAudioSensorPlugin.cc +++ b/src/systems/logical_audio_sensor_plugin/LogicalAudioSensorPlugin.cc @@ -403,14 +403,21 @@ void LogicalAudioSensorPluginPrivate::CreateAudioSource( }; // create services for this source - const auto full_name = scopedName(entity, _ecm); - if (!this->node.Advertise(full_name + "/play", playSrvCb)) + const auto fullName = scopedName(entity, _ecm); + auto validName = transport::TopicUtils::AsValidTopic(fullName); + if (validName.empty()) + { + ignerr << "Failed to create valid topics with entity scoped name [" + << fullName << "]" << std::endl; + return; + } + if (!this->node.Advertise(validName + "/play", playSrvCb)) { ignerr << "Error advertising the play source service for source " << id << " in entity " << _parent << ". " << kSourceSkipMsg; return; } - if (!this->node.Advertise(full_name + "/stop", stopSrvCb)) + if (!this->node.Advertise(validName + "/stop", stopSrvCb)) { ignerr << "Error advertising the stop source service for source " << id << " in entity " << _parent << ". " << kSourceSkipMsg; diff --git a/src/systems/multicopter_control/MulticopterVelocityControl.cc b/src/systems/multicopter_control/MulticopterVelocityControl.cc index edeed38318..9eb4b248b4 100644 --- a/src/systems/multicopter_control/MulticopterVelocityControl.cc +++ b/src/systems/multicopter_control/MulticopterVelocityControl.cc @@ -259,8 +259,15 @@ void MulticopterVelocityControl::Configure(const Entity &_entity, if (sdfClone->HasElement("robotNamespace")) { - this->robotNamespace = - sdfClone->Get("robotNamespace"); + this->robotNamespace = transport::TopicUtils::AsValidTopic( + sdfClone->Get("robotNamespace")); + if (this->robotNamespace.empty()) + { + ignerr << "Robot namespace [" + << sdfClone->Get("robotNamespace") <<"] is invalid." + << std::endl; + return; + } } else { @@ -270,9 +277,23 @@ void MulticopterVelocityControl::Configure(const Entity &_entity, sdfClone->Get("commandSubTopic", this->commandSubTopic, this->commandSubTopic); + this->commandSubTopic = transport::TopicUtils::AsValidTopic( + this->commandSubTopic); + if (this->commandSubTopic.empty()) + { + ignerr << "Invalid command sub-topic." << std::endl; + return; + } sdfClone->Get("enableSubTopic", this->enableSubTopic, this->enableSubTopic); + this->enableSubTopic = transport::TopicUtils::AsValidTopic( + this->enableSubTopic); + if (this->enableSubTopic.empty()) + { + ignerr << "Invalid enable sub-topic." << std::endl; + return; + } // Subscribe to actuator command messages std::string topic{this->robotNamespace + "/" + this->commandSubTopic}; diff --git a/src/systems/multicopter_motor_model/MulticopterMotorModel.cc b/src/systems/multicopter_motor_model/MulticopterMotorModel.cc index 730103d407..dbb5102d00 100644 --- a/src/systems/multicopter_motor_model/MulticopterMotorModel.cc +++ b/src/systems/multicopter_motor_model/MulticopterMotorModel.cc @@ -357,8 +357,14 @@ void MulticopterMotorModel::Configure(const Entity &_entity, this->dataPtr->refMotorInput); // Subscribe to actuator command messages - std::string topic{this->dataPtr->robotNamespace + "/" - + this->dataPtr->commandSubTopic}; + std::string topic = transport::TopicUtils::AsValidTopic( + this->dataPtr->robotNamespace + "/" + this->dataPtr->commandSubTopic); + if (topic.empty()) + { + ignerr << "Failed to create topic for [" << this->dataPtr->robotNamespace + << "]" << std::endl; + return; + } this->dataPtr->node.Subscribe(topic, &MulticopterMotorModelPrivate::OnActuatorMsg, this->dataPtr.get()); } diff --git a/src/systems/scene_broadcaster/SceneBroadcaster.cc b/src/systems/scene_broadcaster/SceneBroadcaster.cc index 576a081bc0..0918c756bb 100644 --- a/src/systems/scene_broadcaster/SceneBroadcaster.cc +++ b/src/systems/scene_broadcaster/SceneBroadcaster.cc @@ -444,8 +444,16 @@ void SceneBroadcasterPrivate::PoseUpdate(const UpdateInfo &_info, ////////////////////////////////////////////////// void SceneBroadcasterPrivate::SetupTransport(const std::string &_worldName) { + auto ns = transport::TopicUtils::AsValidTopic("/world/" + _worldName); + if (ns.empty()) + { + ignerr << "Failed to create valid namespace for world [" << _worldName + << "]" << std::endl; + return; + } + transport::NodeOptions opts; - opts.SetNameSpace("/world/" + _worldName); + opts.SetNameSpace(ns); this->node = std::make_unique(opts); // Scene info service @@ -487,7 +495,7 @@ void SceneBroadcasterPrivate::SetupTransport(const std::string &_worldName) << stateAsyncService << "]" << std::endl; // Scene info topic - std::string sceneTopic{"/world/" + _worldName + "/scene/info"}; + std::string sceneTopic{ns + "/scene/info"}; this->scenePub = this->node->Advertise(sceneTopic); @@ -495,7 +503,7 @@ void SceneBroadcasterPrivate::SetupTransport(const std::string &_worldName) << "]" << std::endl; // Entity deletion publisher - std::string deletionTopic{"/world/" + _worldName + "/scene/deletion"}; + std::string deletionTopic{ns + "/scene/deletion"}; this->deletionPub = this->node->Advertise(deletionTopic); @@ -504,7 +512,7 @@ void SceneBroadcasterPrivate::SetupTransport(const std::string &_worldName) << std::endl; // State topic - std::string stateTopic{"/world/" + _worldName + "/state"}; + std::string stateTopic{ns + "/state"}; this->statePub = this->node->Advertise(stateTopic); diff --git a/src/systems/touch_plugin/TouchPlugin.cc b/src/systems/touch_plugin/TouchPlugin.cc index daa1098aff..ccd177bb90 100644 --- a/src/systems/touch_plugin/TouchPlugin.cc +++ b/src/systems/touch_plugin/TouchPlugin.cc @@ -163,7 +163,14 @@ void TouchPluginPrivate::Load(const EntityComponentManager &_ecm, ignerr << "Missing required parameter " << std::endl; return; } - this->ns = _sdf->Get("namespace"); + this->ns = transport::TopicUtils::AsValidTopic(_sdf->Get( + "namespace")); + if (this->ns.empty()) + { + ignerr << " [" << _sdf->Get("namespace") + << "] is invalid." << std::endl; + return; + } // Target time if (!_sdf->HasElement("time")) diff --git a/src/systems/triggered_publisher/TriggeredPublisher.cc b/src/systems/triggered_publisher/TriggeredPublisher.cc index ddbcb58de7..8fd37edba8 100644 --- a/src/systems/triggered_publisher/TriggeredPublisher.cc +++ b/src/systems/triggered_publisher/TriggeredPublisher.cc @@ -486,10 +486,11 @@ void TriggeredPublisher::Configure(const Entity &, return; } - this->inputTopic = inputElem->Get("topic"); + auto inTopic = inputElem->Get("topic"); + this->inputTopic = transport::TopicUtils::AsValidTopic(inTopic); if (this->inputTopic.empty()) { - ignerr << "Input topic cannot be empty\n"; + ignerr << "Invalid input topic [" << inTopic << "]" << std::endl; return; } @@ -538,10 +539,11 @@ void TriggeredPublisher::Configure(const Entity &, ignerr << "Output message type cannot be empty\n"; continue; } - info.topic = outputElem->Get("topic"); + auto topic = outputElem->Get("topic"); + info.topic = transport::TopicUtils::AsValidTopic(topic); if (info.topic.empty()) { - ignerr << "Output topic cannot be empty\n"; + ignerr << "Invalid topic [" << topic << "]" << std::endl; continue; } const std::string msgStr = outputElem->Get(); diff --git a/src/systems/user_commands/UserCommands.cc b/src/systems/user_commands/UserCommands.cc index 25e1a3ec15..12aa08671a 100644 --- a/src/systems/user_commands/UserCommands.cc +++ b/src/systems/user_commands/UserCommands.cc @@ -223,27 +223,37 @@ void UserCommands::Configure(const Entity &_entity, const components::Name *constCmp = _ecm.Component(_entity); const std::string &worldName = constCmp->Data(); + auto validWorldName = transport::TopicUtils::AsValidTopic(worldName); + if (validWorldName.empty()) + { + ignerr << "World name [" << worldName + << "] doesn't work well with transport, services not advertised." + << std::endl; + return; + } + // Create service - std::string createService{"/world/" + worldName + "/create"}; + std::string createService{"/world/" + validWorldName + "/create"}; this->dataPtr->node.Advertise(createService, &UserCommandsPrivate::CreateService, this->dataPtr.get()); // Create service for EntityFactory_V - std::string createServiceMultiple{"/world/" + worldName + "/create_multiple"}; + std::string createServiceMultiple{"/world/" + validWorldName + + "/create_multiple"}; this->dataPtr->node.Advertise(createServiceMultiple, &UserCommandsPrivate::CreateServiceMultiple, this->dataPtr.get()); ignmsg << "Create service on [" << createService << "]" << std::endl; // Remove service - std::string removeService{"/world/" + worldName + "/remove"}; + std::string removeService{"/world/" + validWorldName + "/remove"}; this->dataPtr->node.Advertise(removeService, &UserCommandsPrivate::RemoveService, this->dataPtr.get()); ignmsg << "Remove service on [" << removeService << "]" << std::endl; // Pose service - std::string poseService{"/world/" + worldName + "/set_pose"}; + std::string poseService{"/world/" + validWorldName + "/set_pose"}; this->dataPtr->node.Advertise(poseService, &UserCommandsPrivate::PoseService, this->dataPtr.get()); diff --git a/src/systems/velocity_control/VelocityControl.cc b/src/systems/velocity_control/VelocityControl.cc index d6e07f48e7..78b1913d67 100644 --- a/src/systems/velocity_control/VelocityControl.cc +++ b/src/systems/velocity_control/VelocityControl.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -26,6 +27,7 @@ #include "ignition/gazebo/components/AngularVelocityCmd.hh" #include "ignition/gazebo/components/LinearVelocityCmd.hh" #include "ignition/gazebo/Model.hh" +#include "ignition/gazebo/Util.hh" #include "VelocityControl.hh" @@ -87,9 +89,13 @@ void VelocityControl::Configure(const Entity &_entity, } // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + "/cmd_vel"}; + std::vector topics; if (_sdf->HasElement("topic")) - topic = _sdf->Get("topic"); + { + topics.push_back(_sdf->Get("topic")); + } + topics.push_back("/model/" + this->dataPtr->model.Name(_ecm) + "/cmd_vel"); + auto topic = validTopic(topics); this->dataPtr->node.Subscribe( topic, &VelocityControlPrivate::OnCmdVel, this->dataPtr.get()); diff --git a/src/systems/wind_effects/WindEffects.cc b/src/systems/wind_effects/WindEffects.cc index 11ba62836d..76a70ea0b3 100644 --- a/src/systems/wind_effects/WindEffects.cc +++ b/src/systems/wind_effects/WindEffects.cc @@ -305,12 +305,20 @@ void WindEffectsPrivate::Load(EntityComponentManager &_ecm, ////////////////////////////////////////////////// void WindEffectsPrivate::SetupTransport(const std::string &_worldName) { + auto validWorldName = transport::TopicUtils::AsValidTopic(_worldName); + if (validWorldName.empty()) + { + ignerr << "Failed to setup transport, invalid world name [" << _worldName + << "]" << std::endl; + return; + } + // Wind seed velocity topic - this->node.Subscribe("/world/" + _worldName + "/wind", + this->node.Subscribe("/world/" + validWorldName + "/wind", &WindEffectsPrivate::OnWindMsg, this); // Wind info service - this->node.Advertise("/world/" + _worldName + "/wind_info", + this->node.Advertise("/world/" + validWorldName + "/wind_info", &WindEffectsPrivate::WindInfoService, this); } From a0aa10cffe5005a91244fc25d60d33623fb146b2 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Thu, 7 Jan 2021 12:18:28 -0600 Subject: [PATCH 13/21] One more tutorial version bump Signed-off-by: Michael Carroll --- tutorials/erb_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/erb_template.md b/tutorials/erb_template.md index b5cf20a1b0..888d621c4e 100644 --- a/tutorials/erb_template.md +++ b/tutorials/erb_template.md @@ -102,7 +102,7 @@ Each box model also has a different name and pose to ensure they show up as indi %> ``` -[Here](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo3/examples/worlds/shapes_population.sdf.erb) is a complete shapes simulation world example. +[Here](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo4/examples/worlds/shapes_population.sdf.erb) is a complete shapes simulation world example. Instead of simple shapes, you can also use a nested loop to generate 100 actors spaced out evenly in a simulation world. From eec149df1dd5891295e7d62571541cd66e708994 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Thu, 7 Jan 2021 12:51:46 -0600 Subject: [PATCH 14/21] Fix bad merge Signed-off-by: Michael Carroll --- src/gui/plugins/scene3d/Scene3D.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index 4e58086c2d..61c60ebd30 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -3103,6 +3103,7 @@ void RenderWindowItem::SetRecordVideoBitrate(unsigned int _bitrate) { this->dataPtr->renderThread->ignRenderer.SetRecordVideoBitrate( _bitrate); +} ///////////////////////////////////////////////// void RenderWindowItem::SetVisibilityMask(uint32_t _mask) From 7db62e619500fd4df31f407668cd6ea73d78b6f7 Mon Sep 17 00:00:00 2001 From: Akash Patel <17132214+acxz@users.noreply.github.com> Date: Thu, 7 Jan 2021 14:01:53 -0500 Subject: [PATCH 15/21] change nullptr to a int ptr for qt 5.15.2 bug (#527) See: https://bugreports.qt.io/browse/QTBUG-89114 Signed-off-by: acxz <17132214+acxz@users.noreply.github.com> Co-authored-by: Louise Poubel Signed-off-by: Louise Poubel --- src/gui/plugins/scene3d/Scene3D.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index 61c60ebd30..6d0a9f2092 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -2138,8 +2138,9 @@ TextureNode::TextureNode(QQuickWindow *_window) #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) this->texture = this->window->createTextureFromId(0, QSize(1, 1)); #else + void * nativeLayout; this->texture = this->window->createTextureFromNativeObject( - QQuickWindow::NativeObjectTexture, nullptr, 0, QSize(1, 1), + QQuickWindow::NativeObjectTexture, &nativeLayout, 0, QSize(1, 1), QQuickWindow::TextureIsOpaque); #endif this->setTexture(this->texture); From 3ea769e1b17c5433de93a99ca86d2c7af21d7da0 Mon Sep 17 00:00:00 2001 From: Louise Poubel Date: Thu, 7 Jan 2021 12:39:27 -0800 Subject: [PATCH 16/21] Generate valid topics everywhere (support names with spaces) (#522) Signed-off-by: Louise Poubel --- CMakeLists.txt | 2 +- examples/worlds/spaces.sdf | 108 ++++++++++++++++++ include/ignition/gazebo/Util.hh | 15 +++ src/LevelManager.cc | 10 +- src/SimulationRunner.cc | 13 ++- src/Util.cc | 22 ++++ src/Util_TEST.cc | 47 +++++++- src/gui/Gui.cc | 33 ++++-- src/gui/GuiRunner.cc | 18 ++- src/gui/plugins/scene3d/Scene3D.cc | 17 +++ .../apply_joint_force/ApplyJointForce.cc | 12 +- .../battery_plugin/LinearBatteryPlugin.cc | 31 ++++- src/systems/breadcrumbs/Breadcrumbs.cc | 13 ++- .../CameraVideoRecorder.cc | 29 ++++- .../detachable_joint/DetachableJoint.cc | 16 ++- src/systems/diff_drive/DiffDrive.cc | 21 +++- .../joint_controller/JointController.cc | 11 +- .../JointPositionController.cc | 12 +- src/systems/log/LogRecord.cc | 24 +++- .../LogicalAudioSensorPlugin.cc | 13 ++- .../MulticopterVelocityControl.cc | 25 +++- .../MulticopterMotorModel.cc | 10 +- .../scene_broadcaster/SceneBroadcaster.cc | 16 ++- src/systems/touch_plugin/TouchPlugin.cc | 9 +- .../triggered_publisher/TriggeredPublisher.cc | 10 +- src/systems/user_commands/UserCommands.cc | 18 ++- .../velocity_control/VelocityControl.cc | 10 +- src/systems/wind_effects/WindEffects.cc | 12 +- 28 files changed, 498 insertions(+), 79 deletions(-) create mode 100644 examples/worlds/spaces.sdf diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b4aaff9e2..b61f207ab6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ set(IGN_FUEL_TOOLS_VER ${ignition-fuel_tools5_VERSION_MAJOR}) #-------------------------------------- # Find ignition-gui -ign_find_package(ignition-gui4 REQUIRED VERSION 4.1) +ign_find_package(ignition-gui4 REQUIRED VERSION 4.1.1) set(IGN_GUI_VER ${ignition-gui4_VERSION_MAJOR}) ign_find_package (Qt5 COMPONENTS diff --git a/examples/worlds/spaces.sdf b/examples/worlds/spaces.sdf new file mode 100644 index 0000000000..0109d50943 --- /dev/null +++ b/examples/worlds/spaces.sdf @@ -0,0 +1,108 @@ + + + + + + 0.001 + 1.0 + + + + + + + + + + 1.0 1.0 1.0 + 0.8 0.8 0.8 + + + + true + 0 0 10 0 0 0 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + 1000 + 0.9 + 0.01 + 0.001 + + -0.5 0.1 -0.9 + + + + true + + + + + 0 0 1 + + + + + + + 0 0 1 + 100 100 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + + + 0 0 0.5 0 0 0 + + + + 1 + 0 + 0 + 1 + 0 + 1 + + 1.0 + + + + + 1 1 1 + + + + + + + + 1 1 1 + + + + 1 0 0 1 + 1 0 0 1 + 1 0 0 1 + + + + + + diff --git a/include/ignition/gazebo/Util.hh b/include/ignition/gazebo/Util.hh index 39d790f7f9..3e9b9c8fec 100644 --- a/include/ignition/gazebo/Util.hh +++ b/include/ignition/gazebo/Util.hh @@ -139,6 +139,21 @@ namespace ignition const Entity &_entity, const EntityComponentManager &_ecm); + /// \brief Helper function to generate a valid transport topic, given + /// a list of topics ordered by preference. The generated topic will be, + /// in this order: + /// + /// 1. The first topic unchanged, if valid. + /// 2. A valid version of the first topic, if possible. + /// 3. The second topic unchanged, if valid. + /// 4. A valid version of the second topic, if possible. + /// 5. ... + /// 6. If no valid topics could be generated, return an empty string. + /// + /// \param[in] _topics Topics ordered by preference. + std::string IGNITION_GAZEBO_VISIBLE validTopic( + const std::vector &_topics); + /// \brief Environment variable holding resource paths. const std::string kResourcePathEnv{"IGN_GAZEBO_RESOURCE_PATH"}; diff --git a/src/LevelManager.cc b/src/LevelManager.cc index d3dcbec7d0..1b54f01848 100644 --- a/src/LevelManager.cc +++ b/src/LevelManager.cc @@ -76,8 +76,14 @@ LevelManager::LevelManager(SimulationRunner *_runner, const bool _useLevels) this->ReadLevelPerformerInfo(); this->CreatePerformers(); - std::string service = "/world/"; - service += this->runner->sdfWorld->Name() + "/level/set_performer"; + std::string service = transport::TopicUtils::AsValidTopic("/world/" + + this->runner->sdfWorld->Name() + "/level/set_performer"); + if (service.empty()) + { + ignerr << "Failed to generate set_performer topic for world [" + << this->runner->sdfWorld->Name() << "]" << std::endl; + return; + } this->node.Advertise(service, &LevelManager::OnSetPerformer, this); } diff --git a/src/SimulationRunner.cc b/src/SimulationRunner.cc index 9777417c33..e047ffaa39 100644 --- a/src/SimulationRunner.cc +++ b/src/SimulationRunner.cc @@ -157,15 +157,20 @@ SimulationRunner::SimulationRunner(const sdf::World *_world, // World control transport::NodeOptions opts; + std::string ns{"/world/" + this->worldName}; if (this->networkMgr) { - opts.SetNameSpace(this->networkMgr->Namespace() + - "/world/" + this->worldName); + ns = this->networkMgr->Namespace() + ns; } - else + + auto validNs = transport::TopicUtils::AsValidTopic(ns); + if (validNs.empty()) { - opts.SetNameSpace("/world/" + this->worldName); + ignerr << "Invalid namespace [" << ns + << "], not initializing runner transport." << std::endl; + return; } + opts.SetNameSpace(validNs); this->node = std::make_unique(opts); diff --git a/src/Util.cc b/src/Util.cc index 5b5995ae9e..828483d0f0 100644 --- a/src/Util.cc +++ b/src/Util.cc @@ -24,6 +24,7 @@ #endif #include #include +#include #include "ignition/gazebo/components/Actor.hh" #include "ignition/gazebo/components/Collision.hh" @@ -416,6 +417,27 @@ ignition::gazebo::Entity topLevelModel(const Entity &_entity, } return entity; } + +////////////////////////////////////////////////// +std::string validTopic(const std::vector &_topics) +{ + for (const auto &topic : _topics) + { + auto validTopic = transport::TopicUtils::AsValidTopic(topic); + if (validTopic.empty()) + { + ignerr << "Topic [" << topic << "] is invalid, ignoring." << std::endl; + continue; + } + if (validTopic != topic) + { + igndbg << "Topic [" << topic << "] changed to valid topic [" + << validTopic << "]" << std::endl; + } + return validTopic; + } + return std::string(); +} } } } diff --git a/src/Util_TEST.cc b/src/Util_TEST.cc index 501fdb5939..d699b3dc3b 100644 --- a/src/Util_TEST.cc +++ b/src/Util_TEST.cc @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -36,8 +37,18 @@ using namespace ignition; using namespace gazebo; +/// \brief Tests for Util.hh +class UtilTest : public ::testing::Test +{ + // Documentation inherited + protected: void SetUp() override + { + common::Console::SetVerbosity(4); + } +}; + ///////////////////////////////////////////////// -TEST(UtilTest, ScopedName) +TEST_F(UtilTest, ScopedName) { EntityComponentManager ecm; @@ -219,7 +230,7 @@ TEST(UtilTest, ScopedName) } ///////////////////////////////////////////////// -TEST(UtilTest, EntityTypeId) +TEST_F(UtilTest, EntityTypeId) { EntityComponentManager ecm; @@ -264,7 +275,7 @@ TEST(UtilTest, EntityTypeId) } ///////////////////////////////////////////////// -TEST(UtilTest, EntityTypeStr) +TEST_F(UtilTest, EntityTypeStr) { EntityComponentManager ecm; @@ -309,7 +320,7 @@ TEST(UtilTest, EntityTypeStr) } ///////////////////////////////////////////////// -TEST(UtilTest, RemoveParentScopedName) +TEST_F(UtilTest, RemoveParentScopedName) { EXPECT_EQ(removeParentScope("world/world_name", "/"), "world_name"); EXPECT_EQ(removeParentScope("world::world_name::light::lightA_name", "::"), @@ -324,7 +335,7 @@ TEST(UtilTest, RemoveParentScopedName) } ///////////////////////////////////////////////// -TEST(UtilTest, AsFullPath) +TEST_F(UtilTest, AsFullPath) { const std::string relativeUriUnix{"meshes/collision.dae"}; const std::string relativeUriWindows{"meshes\\collision.dae"}; @@ -408,7 +419,7 @@ TEST(UtilTest, AsFullPath) } ///////////////////////////////////////////////// -TEST(UtilTest, TopLevelModel) +TEST_F(UtilTest, TopLevelModel) { EntityComponentManager ecm; @@ -463,3 +474,27 @@ TEST(UtilTest, TopLevelModel) // model C should have itself as the top level entity EXPECT_EQ(modelCEntity, topLevelModel(modelCEntity, ecm)); } + +///////////////////////////////////////////////// +TEST_F(UtilTest, ValidTopic) +{ + std::string good{"good"}; + std::string fixable{"not bad~"}; + std::string invalid{"@~@~@~"}; + + EXPECT_EQ("good", validTopic({good})); + EXPECT_EQ("not_bad", validTopic({fixable})); + EXPECT_EQ("", validTopic({invalid})); + + EXPECT_EQ("good", validTopic({good, fixable})); + EXPECT_EQ("not_bad", validTopic({fixable, good})); + + EXPECT_EQ("good", validTopic({good, invalid})); + EXPECT_EQ("good", validTopic({invalid, good})); + + EXPECT_EQ("not_bad", validTopic({fixable, invalid})); + EXPECT_EQ("not_bad", validTopic({invalid, fixable})); + + EXPECT_EQ("not_bad", validTopic({fixable, invalid, good})); + EXPECT_EQ("good", validTopic({invalid, good, fixable})); +} diff --git a/src/gui/Gui.cc b/src/gui/Gui.cc index b375e912fe..1c4912a6d2 100644 --- a/src/gui/Gui.cc +++ b/src/gui/Gui.cc @@ -194,18 +194,31 @@ std::unique_ptr createGui( // Request GUI info for each world result = false; - service = std::string("/world/" + worldName + "/gui/info"); - - igndbg << "Requesting GUI from [" << service << "]..." << std::endl; - - // Request and block ignition::msgs::GUI res; - executed = node.Request(service, timeout, res, result); + service = transport::TopicUtils::AsValidTopic("/world/" + worldName + + "/gui/info"); + if (service.empty()) + { + ignerr << "Failed to generate valid service for world [" << worldName + << "]" << std::endl; + } + else + { + igndbg << "Requesting GUI from [" << service << "]..." << std::endl; - if (!executed) - ignerr << "Service call timed out for [" << service << "]" << std::endl; - else if (!result) - ignerr << "Service call failed for [" << service << "]" << std::endl; + // Request and block + executed = node.Request(service, timeout, res, result); + + if (!executed) + { + ignerr << "Service call timed out for [" << service << "]" + << std::endl; + } + else if (!result) + { + ignerr << "Service call failed for [" << service << "]" << std::endl; + } + } // GUI runner auto runner = new ignition::gazebo::GuiRunner(worldName); diff --git a/src/gui/GuiRunner.cc b/src/gui/GuiRunner.cc index 565838a06c..6f88a441fe 100644 --- a/src/gui/GuiRunner.cc +++ b/src/gui/GuiRunner.cc @@ -40,7 +40,14 @@ GuiRunner::GuiRunner(const std::string &_worldName) winWorldNames.append(QString::fromStdString(_worldName)); win->setProperty("worldNames", winWorldNames); - this->stateTopic = "/world/" + _worldName + "/state"; + this->stateTopic = transport::TopicUtils::AsValidTopic("/world/" + + _worldName + "/state"); + if (this->stateTopic.empty()) + { + ignerr << "Failed to generate valid topic for world [" << _worldName << "]" + << std::endl; + return; + } common::addFindFileURICallback([] (common::URI _uri) { @@ -63,6 +70,15 @@ void GuiRunner::RequestState() std::string id = std::to_string(gui::App()->applicationPid()); std::string reqSrv = this->node.Options().NameSpace() + "/" + id + "/state_async"; + auto reqSrvValid = transport::TopicUtils::AsValidTopic(reqSrv); + if (reqSrvValid.empty()) + { + ignerr << "Failed to generate valid service [" << reqSrv << "]" + << std::endl; + return; + } + reqSrv = reqSrvValid; + this->node.Advertise(reqSrv, &GuiRunner::OnStateAsyncService, this); ignition::msgs::StringMsg req; req.set_data(reqSrv); diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index 6d0a9f2092..3a41bbf814 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -1170,6 +1170,15 @@ void IgnRenderer::HandleModelPlacement() this->dataPtr->createCmdService = "/world/" + this->worldName + "/create"; } + this->dataPtr->createCmdService = transport::TopicUtils::AsValidTopic( + this->dataPtr->createCmdService); + if (this->dataPtr->createCmdService.empty()) + { + ignerr << "Failed to create valid create command service for world [" + << this->worldName <<"]" << std::endl; + return; + } + this->dataPtr->node.Request(this->dataPtr->createCmdService, req, cb); this->dataPtr->isPlacing = false; this->dataPtr->mouseDirty = false; @@ -1388,6 +1397,14 @@ void IgnRenderer::HandleMouseTransformControl() this->dataPtr->poseCmdService = "/world/" + this->worldName + "/set_pose"; } + this->dataPtr->poseCmdService = transport::TopicUtils::AsValidTopic( + this->dataPtr->poseCmdService); + if (this->dataPtr->poseCmdService.empty()) + { + ignerr << "Failed to create valid pose command service for world [" + << this->worldName <<"]" << std::endl; + return; + } this->dataPtr->node.Request(this->dataPtr->poseCmdService, req, cb); } diff --git a/src/systems/apply_joint_force/ApplyJointForce.cc b/src/systems/apply_joint_force/ApplyJointForce.cc index 582d46e101..042f585565 100644 --- a/src/systems/apply_joint_force/ApplyJointForce.cc +++ b/src/systems/apply_joint_force/ApplyJointForce.cc @@ -25,6 +25,7 @@ #include "ignition/gazebo/components/JointForceCmd.hh" #include "ignition/gazebo/Model.hh" +#include "ignition/gazebo/Util.hh" using namespace ignition; using namespace gazebo; @@ -93,8 +94,15 @@ void ApplyJointForce::Configure(const Entity &_entity, } // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + "/joint/" + - this->dataPtr->jointName + "/cmd_force"}; + auto topic = transport::TopicUtils::AsValidTopic("/model/" + + this->dataPtr->model.Name(_ecm) + "/joint/" + this->dataPtr->jointName + + "/cmd_force"); + if (topic.empty()) + { + ignerr << "Failed to create valid topic for [" << this->dataPtr->jointName + << "]" << std::endl; + return; + } this->dataPtr->node.Subscribe(topic, &ApplyJointForcePrivate::OnCmdForce, this->dataPtr.get()); diff --git a/src/systems/battery_plugin/LinearBatteryPlugin.cc b/src/systems/battery_plugin/LinearBatteryPlugin.cc index 47530eff67..8c8f94b32d 100644 --- a/src/systems/battery_plugin/LinearBatteryPlugin.cc +++ b/src/systems/battery_plugin/LinearBatteryPlugin.cc @@ -297,16 +297,28 @@ void LinearBatteryPlugin::Configure(const Entity &_entity, "/battery/" + _sdf->Get("battery_name") + "/recharge/stop"; - this->dataPtr->node.Advertise(enableRechargeTopic, + auto validEnableRechargeTopic = transport::TopicUtils::AsValidTopic( + enableRechargeTopic); + auto validDisableRechargeTopic = transport::TopicUtils::AsValidTopic( + disableRechargeTopic); + if (validEnableRechargeTopic.empty() || validDisableRechargeTopic.empty()) + { + ignerr << "Failed to create valid topics. Not valid: [" + << enableRechargeTopic << "] and [" << disableRechargeTopic + << "]" << std::endl; + return; + } + + this->dataPtr->node.Advertise(validEnableRechargeTopic, &LinearBatteryPluginPrivate::OnEnableRecharge, this->dataPtr.get()); - this->dataPtr->node.Advertise(disableRechargeTopic, + this->dataPtr->node.Advertise(validDisableRechargeTopic, &LinearBatteryPluginPrivate::OnDisableRecharge, this->dataPtr.get()); if (_sdf->HasElement("recharge_by_topic")) { - this->dataPtr->node.Subscribe(enableRechargeTopic, + this->dataPtr->node.Subscribe(validEnableRechargeTopic, &LinearBatteryPluginPrivate::OnEnableRecharge, this->dataPtr.get()); - this->dataPtr->node.Subscribe(disableRechargeTopic, + this->dataPtr->node.Subscribe(validDisableRechargeTopic, &LinearBatteryPluginPrivate::OnDisableRecharge, this->dataPtr.get()); } } @@ -338,10 +350,19 @@ void LinearBatteryPlugin::Configure(const Entity &_entity, // Setup battery state topic std::string stateTopic{"/model/" + this->dataPtr->model.Name(_ecm) + "/battery/" + this->dataPtr->battery->Name() + "/state"}; + + auto validStateTopic = transport::TopicUtils::AsValidTopic(stateTopic); + if (validStateTopic.empty()) + { + ignerr << "Failed to create valid state topic [" + << stateTopic << "]" << std::endl; + return; + } + transport::AdvertiseMessageOptions opts; opts.SetMsgsPerSec(50); this->dataPtr->statePub = this->dataPtr->node.Advertise( - stateTopic, opts); + validStateTopic, opts); } ///////////////////////////////////////////////// diff --git a/src/systems/breadcrumbs/Breadcrumbs.cc b/src/systems/breadcrumbs/Breadcrumbs.cc index a06789d845..ba98482007 100644 --- a/src/systems/breadcrumbs/Breadcrumbs.cc +++ b/src/systems/breadcrumbs/Breadcrumbs.cc @@ -42,6 +42,7 @@ #include "ignition/gazebo/components/Performer.hh" #include "ignition/gazebo/components/Pose.hh" #include "ignition/gazebo/components/World.hh" +#include "ignition/gazebo/Util.hh" using namespace ignition; using namespace gazebo; @@ -132,11 +133,15 @@ void Breadcrumbs::Configure(const Entity &_entity, } // Subscribe to commands - std::string topic{"/model/" + this->model.Name(_ecm) + "/breadcrumbs/" + - this->modelRoot.ModelByIndex(0)->Name() + "/deploy"}; - + std::vector topics; if (_sdf->HasElement("topic")) - topic = _sdf->Get("topic"); + { + topics.push_back(_sdf->Get("topic")); + } + topics.push_back("/model/" + + this->model.Name(_ecm) + "/breadcrumbs/" + + this->modelRoot.ModelByIndex(0)->Name() + "/deploy"); + auto topic = validTopic(topics); this->node.Subscribe(topic, &Breadcrumbs::OnDeploy, this); this->remainingPub = this->node.Advertise(topic + "/remaining"); diff --git a/src/systems/camera_video_recorder/CameraVideoRecorder.cc b/src/systems/camera_video_recorder/CameraVideoRecorder.cc index 52c24ad0f9..cadc7b4b3d 100644 --- a/src/systems/camera_video_recorder/CameraVideoRecorder.cc +++ b/src/systems/camera_video_recorder/CameraVideoRecorder.cc @@ -200,7 +200,13 @@ void CameraVideoRecorder::Configure( // video recorder service topic name if (_sdf->HasElement("service")) { - this->dataPtr->service = _sdf->Get("service"); + this->dataPtr->service = transport::TopicUtils::AsValidTopic( + _sdf->Get("service")); + if (this->dataPtr->service.empty()) + { + ignerr << "Service [" << _sdf->Get("service") + << "] not valid. Ignoring." << std::endl; + } } this->dataPtr->eventMgr = &_eventMgr; @@ -208,7 +214,15 @@ void CameraVideoRecorder::Configure( sdf::Sensor sensorSdf = cameraEntComp->Data(); std::string topic = sensorSdf.Topic(); if (topic.empty()) - topic = scopedName(_entity, _ecm) + "/image"; + { + auto scoped = scopedName(_entity, _ecm); + topic = transport::TopicUtils::AsValidTopic(scoped + "/image"); + if (topic.empty()) + { + ignerr << "Failed to generate valid topic for entity [" << scoped + << "]" << std::endl; + } + } this->dataPtr->sensorTopic = topic; } @@ -363,8 +377,15 @@ void CameraVideoRecorder::PostUpdate(const UpdateInfo &, if (this->dataPtr->service.empty()) { - this->dataPtr->service = scopedName(this->dataPtr->entity, _ecm) + - "/record_video"; + auto scoped = scopedName(this->dataPtr->entity, _ecm); + this->dataPtr->service = transport::TopicUtils::AsValidTopic(scoped + + "/record_video"); + if (this->dataPtr->service.empty()) + { + ignerr << "Failed to create valid service for [" << scoped << "]" + << std::endl; + } + return; } this->dataPtr->node.Advertise(this->dataPtr->service, diff --git a/src/systems/detachable_joint/DetachableJoint.cc b/src/systems/detachable_joint/DetachableJoint.cc index 1ed2125a1f..0946aa9505 100644 --- a/src/systems/detachable_joint/DetachableJoint.cc +++ b/src/systems/detachable_joint/DetachableJoint.cc @@ -15,6 +15,8 @@ * */ +#include + #include #include @@ -22,13 +24,14 @@ #include -#include "ignition/gazebo/Model.hh" #include "ignition/gazebo/components/DetachableJoint.hh" #include "ignition/gazebo/components/Link.hh" #include "ignition/gazebo/components/Model.hh" #include "ignition/gazebo/components/Name.hh" #include "ignition/gazebo/components/ParentEntity.hh" #include "ignition/gazebo/components/Pose.hh" +#include "ignition/gazebo/Model.hh" +#include "ignition/gazebo/Util.hh" #include "DetachableJoint.hh" @@ -93,9 +96,14 @@ void DetachableJoint::Configure(const Entity &_entity, } // Setup detach topic - std::string defaultTopic{"/model/" + this->model.Name(_ecm) + - "/detachable_joint/detach"}; - this->topic = _sdf->Get("topic", defaultTopic).first; + std::vector topics; + if (_sdf->HasElement("topic")) + { + topics.push_back(_sdf->Get("topic")); + } + topics.push_back("/model/" + this->model.Name(_ecm) + + "/detachable_joint/detach"); + this->topic = validTopic(topics); this->suppressChildWarning = _sdf->Get("suppress_child_warning", this->suppressChildWarning) diff --git a/src/systems/diff_drive/DiffDrive.cc b/src/systems/diff_drive/DiffDrive.cc index 007ba2e76e..917d65bf15 100644 --- a/src/systems/diff_drive/DiffDrive.cc +++ b/src/systems/diff_drive/DiffDrive.cc @@ -36,6 +36,7 @@ #include "ignition/gazebo/components/JointVelocityCmd.hh" #include "ignition/gazebo/Link.hh" #include "ignition/gazebo/Model.hh" +#include "ignition/gazebo/Util.hh" #include "SpeedLimiter.hh" @@ -259,16 +260,26 @@ void DiffDrive::Configure(const Entity &_entity, this->dataPtr->wheelRadius, this->dataPtr->wheelRadius); // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + "/cmd_vel"}; + std::vector topics; if (_sdf->HasElement("topic")) - topic = _sdf->Get("topic"); + { + topics.push_back(_sdf->Get("topic")); + } + topics.push_back("/model/" + this->dataPtr->model.Name(_ecm) + "/cmd_vel"); + auto topic = validTopic(topics); + this->dataPtr->node.Subscribe(topic, &DiffDrivePrivate::OnCmdVel, this->dataPtr.get()); - std::string odomTopic{"/model/" + this->dataPtr->model.Name(_ecm) + - "/odometry"}; + std::vector odomTopics; if (_sdf->HasElement("odom_topic")) - odomTopic = _sdf->Get("odom_topic"); + { + odomTopics.push_back(_sdf->Get("odom_topic")); + } + odomTopics.push_back("/model/" + this->dataPtr->model.Name(_ecm) + + "/odometry"); + auto odomTopic = validTopic(odomTopics); + this->dataPtr->odomPub = this->dataPtr->node.Advertise( odomTopic); diff --git a/src/systems/joint_controller/JointController.cc b/src/systems/joint_controller/JointController.cc index 42990d4447..dd2f645f1d 100644 --- a/src/systems/joint_controller/JointController.cc +++ b/src/systems/joint_controller/JointController.cc @@ -131,8 +131,15 @@ void JointController::Configure(const Entity &_entity, } // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + "/joint/" + - this->dataPtr->jointName + "/cmd_vel"}; + std::string topic = transport::TopicUtils::AsValidTopic("/model/" + + this->dataPtr->model.Name(_ecm) + "/joint/" + this->dataPtr->jointName + + "/cmd_vel"); + if (topic.empty()) + { + ignerr << "Failed to create topic for joint [" << this->dataPtr->jointName + << "]" << std::endl; + return; + } this->dataPtr->node.Subscribe(topic, &JointControllerPrivate::OnCmdVel, this->dataPtr.get()); diff --git a/src/systems/joint_position_controller/JointPositionController.cc b/src/systems/joint_position_controller/JointPositionController.cc index c048ff0e23..5eaefaf45e 100644 --- a/src/systems/joint_position_controller/JointPositionController.cc +++ b/src/systems/joint_position_controller/JointPositionController.cc @@ -147,9 +147,15 @@ void JointPositionController::Configure(const Entity &_entity, this->dataPtr->posPid.Init(p, i, d, iMax, iMin, cmdMax, cmdMin, cmdOffset); // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + - "/joint/" + this->dataPtr->jointName + "/" + - std::to_string(this->dataPtr->jointIndex) + "/cmd_pos"}; + std::string topic = transport::TopicUtils::AsValidTopic("/model/" + + this->dataPtr->model.Name(_ecm) + "/joint/" + this->dataPtr->jointName + + "/" + std::to_string(this->dataPtr->jointIndex) + "/cmd_pos"); + if (topic.empty()) + { + ignerr << "Failed to create topic for joint [" << this->dataPtr->jointName + << "]" << std::endl; + return; + } this->dataPtr->node.Subscribe( topic, &JointPositionControllerPrivate::OnCmdPos, this->dataPtr.get()); diff --git a/src/systems/log/LogRecord.cc b/src/systems/log/LogRecord.cc index 233d7049a9..3febe2343a 100644 --- a/src/systems/log/LogRecord.cc +++ b/src/systems/log/LogRecord.cc @@ -291,11 +291,31 @@ bool LogRecordPrivate::Start(const std::string &_logPath, // Use directory basename as topic name, to be able to retrieve at playback std::string sdfTopic = "/" + common::basename(this->logPath) + "/sdf"; - this->sdfPub = this->node.Advertise(sdfTopic, this->sdfMsg.GetTypeName()); + auto validSdfTopic = transport::TopicUtils::AsValidTopic(sdfTopic); + if (!validSdfTopic.empty()) + { + this->sdfPub = this->node.Advertise(validSdfTopic, + this->sdfMsg.GetTypeName()); + } + else + { + ignerr << "Failed to generate valid topic to publish SDF. Tried [" + << sdfTopic << "]." << std::endl; + } // TODO(louise) Combine with SceneBroadcaster's state topic std::string stateTopic = "/world/" + this->worldName + "/changed_state"; - this->statePub = this->node.Advertise(stateTopic); + auto validStateTopic = transport::TopicUtils::AsValidTopic(stateTopic); + if (!validStateTopic.empty()) + { + this->statePub = this->node.Advertise( + validStateTopic); + } + else + { + ignerr << "Failed to generate valid topic to publish state. Tried [" + << stateTopic << "]." << std::endl; + } // Append file name std::string dbPath = common::joinPaths(this->logPath, "state.tlog"); diff --git a/src/systems/logical_audio_sensor_plugin/LogicalAudioSensorPlugin.cc b/src/systems/logical_audio_sensor_plugin/LogicalAudioSensorPlugin.cc index 33b9310b2b..78ab1b7d65 100644 --- a/src/systems/logical_audio_sensor_plugin/LogicalAudioSensorPlugin.cc +++ b/src/systems/logical_audio_sensor_plugin/LogicalAudioSensorPlugin.cc @@ -403,14 +403,21 @@ void LogicalAudioSensorPluginPrivate::CreateAudioSource( }; // create services for this source - const auto full_name = scopedName(entity, _ecm); - if (!this->node.Advertise(full_name + "/play", playSrvCb)) + const auto fullName = scopedName(entity, _ecm); + auto validName = transport::TopicUtils::AsValidTopic(fullName); + if (validName.empty()) + { + ignerr << "Failed to create valid topics with entity scoped name [" + << fullName << "]" << std::endl; + return; + } + if (!this->node.Advertise(validName + "/play", playSrvCb)) { ignerr << "Error advertising the play source service for source " << id << " in entity " << _parent << ". " << kSourceSkipMsg; return; } - if (!this->node.Advertise(full_name + "/stop", stopSrvCb)) + if (!this->node.Advertise(validName + "/stop", stopSrvCb)) { ignerr << "Error advertising the stop source service for source " << id << " in entity " << _parent << ". " << kSourceSkipMsg; diff --git a/src/systems/multicopter_control/MulticopterVelocityControl.cc b/src/systems/multicopter_control/MulticopterVelocityControl.cc index edeed38318..9eb4b248b4 100644 --- a/src/systems/multicopter_control/MulticopterVelocityControl.cc +++ b/src/systems/multicopter_control/MulticopterVelocityControl.cc @@ -259,8 +259,15 @@ void MulticopterVelocityControl::Configure(const Entity &_entity, if (sdfClone->HasElement("robotNamespace")) { - this->robotNamespace = - sdfClone->Get("robotNamespace"); + this->robotNamespace = transport::TopicUtils::AsValidTopic( + sdfClone->Get("robotNamespace")); + if (this->robotNamespace.empty()) + { + ignerr << "Robot namespace [" + << sdfClone->Get("robotNamespace") <<"] is invalid." + << std::endl; + return; + } } else { @@ -270,9 +277,23 @@ void MulticopterVelocityControl::Configure(const Entity &_entity, sdfClone->Get("commandSubTopic", this->commandSubTopic, this->commandSubTopic); + this->commandSubTopic = transport::TopicUtils::AsValidTopic( + this->commandSubTopic); + if (this->commandSubTopic.empty()) + { + ignerr << "Invalid command sub-topic." << std::endl; + return; + } sdfClone->Get("enableSubTopic", this->enableSubTopic, this->enableSubTopic); + this->enableSubTopic = transport::TopicUtils::AsValidTopic( + this->enableSubTopic); + if (this->enableSubTopic.empty()) + { + ignerr << "Invalid enable sub-topic." << std::endl; + return; + } // Subscribe to actuator command messages std::string topic{this->robotNamespace + "/" + this->commandSubTopic}; diff --git a/src/systems/multicopter_motor_model/MulticopterMotorModel.cc b/src/systems/multicopter_motor_model/MulticopterMotorModel.cc index 730103d407..dbb5102d00 100644 --- a/src/systems/multicopter_motor_model/MulticopterMotorModel.cc +++ b/src/systems/multicopter_motor_model/MulticopterMotorModel.cc @@ -357,8 +357,14 @@ void MulticopterMotorModel::Configure(const Entity &_entity, this->dataPtr->refMotorInput); // Subscribe to actuator command messages - std::string topic{this->dataPtr->robotNamespace + "/" - + this->dataPtr->commandSubTopic}; + std::string topic = transport::TopicUtils::AsValidTopic( + this->dataPtr->robotNamespace + "/" + this->dataPtr->commandSubTopic); + if (topic.empty()) + { + ignerr << "Failed to create topic for [" << this->dataPtr->robotNamespace + << "]" << std::endl; + return; + } this->dataPtr->node.Subscribe(topic, &MulticopterMotorModelPrivate::OnActuatorMsg, this->dataPtr.get()); } diff --git a/src/systems/scene_broadcaster/SceneBroadcaster.cc b/src/systems/scene_broadcaster/SceneBroadcaster.cc index 9dde20341b..7e5094cc0d 100644 --- a/src/systems/scene_broadcaster/SceneBroadcaster.cc +++ b/src/systems/scene_broadcaster/SceneBroadcaster.cc @@ -449,8 +449,16 @@ void SceneBroadcasterPrivate::PoseUpdate(const UpdateInfo &_info, ////////////////////////////////////////////////// void SceneBroadcasterPrivate::SetupTransport(const std::string &_worldName) { + auto ns = transport::TopicUtils::AsValidTopic("/world/" + _worldName); + if (ns.empty()) + { + ignerr << "Failed to create valid namespace for world [" << _worldName + << "]" << std::endl; + return; + } + transport::NodeOptions opts; - opts.SetNameSpace("/world/" + _worldName); + opts.SetNameSpace(ns); this->node = std::make_unique(opts); // Scene info service @@ -492,7 +500,7 @@ void SceneBroadcasterPrivate::SetupTransport(const std::string &_worldName) << stateAsyncService << "]" << std::endl; // Scene info topic - std::string sceneTopic{"/world/" + _worldName + "/scene/info"}; + std::string sceneTopic{ns + "/scene/info"}; this->scenePub = this->node->Advertise(sceneTopic); @@ -500,7 +508,7 @@ void SceneBroadcasterPrivate::SetupTransport(const std::string &_worldName) << "]" << std::endl; // Entity deletion publisher - std::string deletionTopic{"/world/" + _worldName + "/scene/deletion"}; + std::string deletionTopic{ns + "/scene/deletion"}; this->deletionPub = this->node->Advertise(deletionTopic); @@ -509,7 +517,7 @@ void SceneBroadcasterPrivate::SetupTransport(const std::string &_worldName) << std::endl; // State topic - std::string stateTopic{"/world/" + _worldName + "/state"}; + std::string stateTopic{ns + "/state"}; this->statePub = this->node->Advertise(stateTopic); diff --git a/src/systems/touch_plugin/TouchPlugin.cc b/src/systems/touch_plugin/TouchPlugin.cc index daa1098aff..ccd177bb90 100644 --- a/src/systems/touch_plugin/TouchPlugin.cc +++ b/src/systems/touch_plugin/TouchPlugin.cc @@ -163,7 +163,14 @@ void TouchPluginPrivate::Load(const EntityComponentManager &_ecm, ignerr << "Missing required parameter " << std::endl; return; } - this->ns = _sdf->Get("namespace"); + this->ns = transport::TopicUtils::AsValidTopic(_sdf->Get( + "namespace")); + if (this->ns.empty()) + { + ignerr << " [" << _sdf->Get("namespace") + << "] is invalid." << std::endl; + return; + } // Target time if (!_sdf->HasElement("time")) diff --git a/src/systems/triggered_publisher/TriggeredPublisher.cc b/src/systems/triggered_publisher/TriggeredPublisher.cc index ddbcb58de7..8fd37edba8 100644 --- a/src/systems/triggered_publisher/TriggeredPublisher.cc +++ b/src/systems/triggered_publisher/TriggeredPublisher.cc @@ -486,10 +486,11 @@ void TriggeredPublisher::Configure(const Entity &, return; } - this->inputTopic = inputElem->Get("topic"); + auto inTopic = inputElem->Get("topic"); + this->inputTopic = transport::TopicUtils::AsValidTopic(inTopic); if (this->inputTopic.empty()) { - ignerr << "Input topic cannot be empty\n"; + ignerr << "Invalid input topic [" << inTopic << "]" << std::endl; return; } @@ -538,10 +539,11 @@ void TriggeredPublisher::Configure(const Entity &, ignerr << "Output message type cannot be empty\n"; continue; } - info.topic = outputElem->Get("topic"); + auto topic = outputElem->Get("topic"); + info.topic = transport::TopicUtils::AsValidTopic(topic); if (info.topic.empty()) { - ignerr << "Output topic cannot be empty\n"; + ignerr << "Invalid topic [" << topic << "]" << std::endl; continue; } const std::string msgStr = outputElem->Get(); diff --git a/src/systems/user_commands/UserCommands.cc b/src/systems/user_commands/UserCommands.cc index 25e1a3ec15..12aa08671a 100644 --- a/src/systems/user_commands/UserCommands.cc +++ b/src/systems/user_commands/UserCommands.cc @@ -223,27 +223,37 @@ void UserCommands::Configure(const Entity &_entity, const components::Name *constCmp = _ecm.Component(_entity); const std::string &worldName = constCmp->Data(); + auto validWorldName = transport::TopicUtils::AsValidTopic(worldName); + if (validWorldName.empty()) + { + ignerr << "World name [" << worldName + << "] doesn't work well with transport, services not advertised." + << std::endl; + return; + } + // Create service - std::string createService{"/world/" + worldName + "/create"}; + std::string createService{"/world/" + validWorldName + "/create"}; this->dataPtr->node.Advertise(createService, &UserCommandsPrivate::CreateService, this->dataPtr.get()); // Create service for EntityFactory_V - std::string createServiceMultiple{"/world/" + worldName + "/create_multiple"}; + std::string createServiceMultiple{"/world/" + validWorldName + + "/create_multiple"}; this->dataPtr->node.Advertise(createServiceMultiple, &UserCommandsPrivate::CreateServiceMultiple, this->dataPtr.get()); ignmsg << "Create service on [" << createService << "]" << std::endl; // Remove service - std::string removeService{"/world/" + worldName + "/remove"}; + std::string removeService{"/world/" + validWorldName + "/remove"}; this->dataPtr->node.Advertise(removeService, &UserCommandsPrivate::RemoveService, this->dataPtr.get()); ignmsg << "Remove service on [" << removeService << "]" << std::endl; // Pose service - std::string poseService{"/world/" + worldName + "/set_pose"}; + std::string poseService{"/world/" + validWorldName + "/set_pose"}; this->dataPtr->node.Advertise(poseService, &UserCommandsPrivate::PoseService, this->dataPtr.get()); diff --git a/src/systems/velocity_control/VelocityControl.cc b/src/systems/velocity_control/VelocityControl.cc index d6e07f48e7..78b1913d67 100644 --- a/src/systems/velocity_control/VelocityControl.cc +++ b/src/systems/velocity_control/VelocityControl.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -26,6 +27,7 @@ #include "ignition/gazebo/components/AngularVelocityCmd.hh" #include "ignition/gazebo/components/LinearVelocityCmd.hh" #include "ignition/gazebo/Model.hh" +#include "ignition/gazebo/Util.hh" #include "VelocityControl.hh" @@ -87,9 +89,13 @@ void VelocityControl::Configure(const Entity &_entity, } // Subscribe to commands - std::string topic{"/model/" + this->dataPtr->model.Name(_ecm) + "/cmd_vel"}; + std::vector topics; if (_sdf->HasElement("topic")) - topic = _sdf->Get("topic"); + { + topics.push_back(_sdf->Get("topic")); + } + topics.push_back("/model/" + this->dataPtr->model.Name(_ecm) + "/cmd_vel"); + auto topic = validTopic(topics); this->dataPtr->node.Subscribe( topic, &VelocityControlPrivate::OnCmdVel, this->dataPtr.get()); diff --git a/src/systems/wind_effects/WindEffects.cc b/src/systems/wind_effects/WindEffects.cc index 11ba62836d..76a70ea0b3 100644 --- a/src/systems/wind_effects/WindEffects.cc +++ b/src/systems/wind_effects/WindEffects.cc @@ -305,12 +305,20 @@ void WindEffectsPrivate::Load(EntityComponentManager &_ecm, ////////////////////////////////////////////////// void WindEffectsPrivate::SetupTransport(const std::string &_worldName) { + auto validWorldName = transport::TopicUtils::AsValidTopic(_worldName); + if (validWorldName.empty()) + { + ignerr << "Failed to setup transport, invalid world name [" << _worldName + << "]" << std::endl; + return; + } + // Wind seed velocity topic - this->node.Subscribe("/world/" + _worldName + "/wind", + this->node.Subscribe("/world/" + validWorldName + "/wind", &WindEffectsPrivate::OnWindMsg, this); // Wind info service - this->node.Advertise("/world/" + _worldName + "/wind_info", + this->node.Advertise("/world/" + validWorldName + "/wind_info", &WindEffectsPrivate::WindInfoService, this); } From 320f0c9f35c3aee28a7be351df86c3a00c0fee9f Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Thu, 7 Jan 2021 15:46:32 -0600 Subject: [PATCH 17/21] Change deprecated test case->suite Signed-off-by: Michael Carroll --- test/integration/follow_actor_system.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/follow_actor_system.cc b/test/integration/follow_actor_system.cc index 28ca5191c1..654e578c85 100644 --- a/test/integration/follow_actor_system.cc +++ b/test/integration/follow_actor_system.cc @@ -187,5 +187,5 @@ TEST_P(FollowActorTest, PublishCmd) } // Run multiple times -INSTANTIATE_TEST_CASE_P(ServerRepeat, FollowActorTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, FollowActorTest, ::testing::Range(1, 2)); From dfb97f4ee98c6c8f7894e00df0607cf033836b87 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Fri, 8 Jan 2021 08:18:54 -0600 Subject: [PATCH 18/21] =?UTF-8?q?3=20=E2=9E=A1=EF=B8=8F=204=20(#533)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Clarify how sim time is interpreted in a System's step (#467) * add frame_id and child_frame_id attribute support for DiffDrive (#361) * Add ability to record video based on sim time (#414) * add ability to record video from gui camera using sim time * add msg * use QueryBoolText * Add lockstep mode to video recording (#419) * Disable right click menu when using measuring tool (#458) * Bump to 3.6.0 (#524) * Don't make docs on macOS (#528) * Updates to ardupilot migration tutorial (#525) * Update gtest to 1.10.0 for Windows compilation (ign-gazebo3) (#506) * Compile new gtest with c++11 * Use INSTANTIATE_TEST_SUITE_P instead of deprecated -INSTANTIATE_TEST_CASE_P * Apply suggestions from code review * One more tutorial version bump * Fix bad merge * change nullptr to a int ptr for qt 5.15.2 bug (#527) * Generate valid topics everywhere (support names with spaces) (#522) * Change deprecated test case->suite Co-authored-by: Ashton Larkin Co-authored-by: G.Doisy Co-authored-by: Ian Chen Co-authored-by: Nate Koenig Co-authored-by: Louise Poubel Co-authored-by: John Shepherd Co-authored-by: Steve Peters Co-authored-by: Jose Luis Rivero Co-authored-by: Akash Patel <17132214+acxz@users.noreply.github.com> --- CMakeLists.txt | 31 +- Changelog.md | 62 + include/ignition/gazebo/System.hh | 27 +- .../ignition/gazebo/rendering/RenderUtil.hh | 5 + src/EntityComponentManager_TEST.cc | 2 +- src/Server_TEST.cc | 2 +- src/SimulationRunner_TEST.cc | 2 +- src/gui/plugins/scene3d/Scene3D.cc | 281 +- src/gui/plugins/scene3d/Scene3D.hh | 43 + src/gui/plugins/tape_measure/TapeMeasure.cc | 32 + src/rendering/RenderUtil.cc | 7 + src/systems/diff_drive/DiffDrive.cc | 35 +- .../scene_broadcaster/SceneBroadcaster.cc | 5 + test/CMakeLists.txt | 1 + test/gtest/cmake/Config.cmake.in | 9 + test/gtest/cmake/gtest.pc.in | 10 + test/gtest/cmake/gtest_main.pc.in | 11 + test/gtest/cmake/internal_utils.cmake | 197 +- test/gtest/cmake/libgtest.la.in | 21 + test/gtest/gtest-1.10.0.diff | 15 + test/gtest/gtest-1.7.0.diff | 44 - test/gtest/include/gtest/gtest-death-test.h | 71 +- test/gtest/include/gtest/gtest-matchers.h | 750 ++++ test/gtest/include/gtest/gtest-message.h | 56 +- test/gtest/include/gtest/gtest-param-test.h | 1208 +------ .../include/gtest/gtest-param-test.h.pump | 64 +- test/gtest/include/gtest/gtest-printers.h | 536 +-- test/gtest/include/gtest/gtest-spi.h | 20 +- test/gtest/include/gtest/gtest-test-part.h | 43 +- test/gtest/include/gtest/gtest-typed-test.h | 252 +- test/gtest/include/gtest/gtest.h | 1191 ++++--- test/gtest/include/gtest/gtest_pred_impl.h | 81 +- test/gtest/include/gtest/gtest_prod.h | 17 +- .../include/gtest/internal/custom/README.md | 56 + .../gtest/internal/custom/gtest-port.h | 37 + .../gtest/internal/custom/gtest-printers.h | 42 + .../include/gtest/internal/custom/gtest.h | 37 + .../internal/gtest-death-test-internal.h | 175 +- .../include/gtest/internal/gtest-filepath.h | 13 +- .../include/gtest/internal/gtest-internal.h | 842 +++-- .../include/gtest/internal/gtest-linked_ptr.h | 14 +- .../internal/gtest-param-util-generated.h | 158 +- .../gtest-param-util-generated.h.pump | 42 +- .../include/gtest/internal/gtest-param-util.h | 584 ++- .../include/gtest/internal/gtest-port-arch.h | 107 + .../gtest/include/gtest/internal/gtest-port.h | 1557 ++++---- .../include/gtest/internal/gtest-string.h | 30 +- .../include/gtest/internal/gtest-tuple.h | 8 + .../include/gtest/internal/gtest-tuple.h.pump | 8 + .../include/gtest/internal/gtest-type-util.h | 42 +- .../gtest/internal/gtest-type-util.h.pump | 43 +- test/gtest/src/gtest-all.cc | 6 +- test/gtest/src/gtest-death-test.cc | 601 +++- test/gtest/src/gtest-filepath.cc | 47 +- test/gtest/src/gtest-internal-inl.h | 339 +- test/gtest/src/gtest-matchers.cc | 97 + test/gtest/src/gtest-port.cc | 844 ++++- test/gtest/src/gtest-printers.cc | 131 +- test/gtest/src/gtest-test-part.cc | 34 +- test/gtest/src/gtest-typed-test.cc | 48 +- test/gtest/src/gtest.cc | 3139 +++++++++++------ test/gtest/src/gtest_main.cc | 17 +- test/integration/diff_drive_system.cc | 109 +- test/integration/examples_build.cc | 2 +- test/integration/follow_actor_system.cc | 2 +- test/integration/scene_broadcaster_system.cc | 2 +- test/integration/velocity_control_system.cc | 2 +- test/worlds/diff_drive_custom_frame_id.sdf | 245 ++ tutorials.md.in | 1 + tutorials/create_system_plugins.md | 21 +- tutorials/erb_template.md | 2 +- .../files/video_recorder/video_recorder.gif | Bin 0 -> 222842 bytes .../files/video_recorder/video_recorder.png | Bin 0 -> 47398 bytes tutorials/migrating_ardupilot_plugin.md | 107 +- tutorials/video_recorder.md | 107 + 75 files changed, 9683 insertions(+), 5146 deletions(-) create mode 100644 test/gtest/cmake/Config.cmake.in create mode 100644 test/gtest/cmake/gtest.pc.in create mode 100644 test/gtest/cmake/gtest_main.pc.in create mode 100644 test/gtest/cmake/libgtest.la.in create mode 100644 test/gtest/gtest-1.10.0.diff delete mode 100644 test/gtest/gtest-1.7.0.diff create mode 100644 test/gtest/include/gtest/gtest-matchers.h create mode 100644 test/gtest/include/gtest/internal/custom/README.md create mode 100644 test/gtest/include/gtest/internal/custom/gtest-port.h create mode 100644 test/gtest/include/gtest/internal/custom/gtest-printers.h create mode 100644 test/gtest/include/gtest/internal/custom/gtest.h create mode 100644 test/gtest/include/gtest/internal/gtest-port-arch.h create mode 100644 test/gtest/src/gtest-matchers.cc create mode 100644 test/worlds/diff_drive_custom_frame_id.sdf create mode 100644 tutorials/files/video_recorder/video_recorder.gif create mode 100644 tutorials/files/video_recorder/video_recorder.png create mode 100644 tutorials/video_recorder.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d4f036811..b61f207ab6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,19 +158,24 @@ ign_create_packages() configure_file(${CMAKE_SOURCE_DIR}/api.md.in ${CMAKE_BINARY_DIR}/api.md) configure_file(${CMAKE_SOURCE_DIR}/tutorials.md.in ${CMAKE_BINARY_DIR}/tutorials.md) -ign_create_docs( - API_MAINPAGE_MD "${CMAKE_BINARY_DIR}/api.md" - TUTORIALS_MAINPAGE_MD "${CMAKE_BINARY_DIR}/tutorials.md" - ADDITIONAL_INPUT_DIRS "${CMAKE_SOURCE_DIR}/src/systems ${CMAKE_SOURCE_DIR}/src/gui/plugins" - TAGFILES - "${IGNITION-MATH_DOXYGEN_TAGFILE} = ${IGNITION-MATH_API_URL}" - "${IGNITION-MSGS_DOXYGEN_TAGFILE} = ${IGNITION-MSGS_API_URL}" - "${IGNITION-PHYSICS_DOXYGEN_TAGFILE} = ${IGNITION-PHYSICS_API_URL}" - "${IGNITION-PLUGIN_DOXYGEN_TAGFILE} = ${IGNITION-PLUGIN_API_URL}" - "${IGNITION-TRANSPORT_DOXYGEN_TAGFILE} = ${IGNITION-TRANSPORT_API_URL}" - "${IGNITION-SENSORS_DOXYGEN_TAGFILE} = ${IGNITION-SENSORS_API_URL}" - "${IGNITION-COMMON_DOXYGEN_TAGFILE} = ${IGNITION-COMMON_API_URL}" -) +# disable doxygen on macOS due to issues with doxygen 1.9.0 +# there is an unreleased fix; revert this when 1.9.1 is released +# https://github.com/ignitionrobotics/ign-gazebo/issues/520 +if (NOT APPLE) + ign_create_docs( + API_MAINPAGE_MD "${CMAKE_BINARY_DIR}/api.md" + TUTORIALS_MAINPAGE_MD "${CMAKE_BINARY_DIR}/tutorials.md" + ADDITIONAL_INPUT_DIRS "${CMAKE_SOURCE_DIR}/src/systems ${CMAKE_SOURCE_DIR}/src/gui/plugins" + TAGFILES + "${IGNITION-MATH_DOXYGEN_TAGFILE} = ${IGNITION-MATH_API_URL}" + "${IGNITION-MSGS_DOXYGEN_TAGFILE} = ${IGNITION-MSGS_API_URL}" + "${IGNITION-PHYSICS_DOXYGEN_TAGFILE} = ${IGNITION-PHYSICS_API_URL}" + "${IGNITION-PLUGIN_DOXYGEN_TAGFILE} = ${IGNITION-PLUGIN_API_URL}" + "${IGNITION-TRANSPORT_DOXYGEN_TAGFILE} = ${IGNITION-TRANSPORT_API_URL}" + "${IGNITION-SENSORS_DOXYGEN_TAGFILE} = ${IGNITION-SENSORS_API_URL}" + "${IGNITION-COMMON_DOXYGEN_TAGFILE} = ${IGNITION-COMMON_API_URL}" + ) +endif() if(TARGET doc) file(COPY ${CMAKE_SOURCE_DIR}/tutorials/files/ DESTINATION ${CMAKE_BINARY_DIR}/doxygen/html/files/) diff --git a/Changelog.md b/Changelog.md index 5b67d1e746..7508cae2a5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -157,6 +157,68 @@ ### Ignition Gazebo 3.X.X (20XX-XX-XX) +### Ignition Gazebo 3.6.0 (2020-12-30) + +1. Fix pose msg conversion when msg is missing orientation + * [Pull Request 450](https://github.com/ignitionrobotics/ign-gazebo/pull/450) + +1. Address code checker warnings + * [Pull Request 443](https://github.com/ignitionrobotics/ign-gazebo/pull/443) + * [Pull Request 491](https://github.com/ignitionrobotics/ign-gazebo/pull/491) + * [Pull Request 499](https://github.com/ignitionrobotics/ign-gazebo/pull/499) + * [Pull Request 502](https://github.com/ignitionrobotics/ign-gazebo/pull/502) + +1. Test fixes + * [Pull Request 455](https://github.com/ignitionrobotics/ign-gazebo/pull/455) + * [Pull Request 463](https://github.com/ignitionrobotics/ign-gazebo/pull/463) + * [Pull Request 452](https://github.com/ignitionrobotics/ign-gazebo/pull/452) + * [Pull Request 480](https://github.com/ignitionrobotics/ign-gazebo/pull/480) + +1. Documentation updates + * [Pull Request 472](https://github.com/ignitionrobotics/ign-gazebo/pull/472) + +1. Fix segfault in the Breadcrumb system when associated model is unloaded + * [Pull Request 454](https://github.com/ignitionrobotics/ign-gazebo/pull/454) + +1. Added user commands to example thermal camera world + * [Pull Request 442](https://github.com/ignitionrobotics/ign-gazebo/pull/442) + +1. Helper function to set component data + * [Pull Request 436](https://github.com/ignitionrobotics/ign-gazebo/pull/436) + +1. Remove unneeded if statement in EntityComponentManager + * [Pull Request 432](https://github.com/ignitionrobotics/ign-gazebo/pull/432) + +1. Clarify how time is represented in each phase of a System step + * [Pull Request 467](https://github.com/ignitionrobotics/ign-gazebo/pull/467) + +1. Switch to async state service request + * [Pull Request 461](https://github.com/ignitionrobotics/ign-gazebo/pull/461) + +1. Update key event handling + * [Pull Request 466](https://github.com/ignitionrobotics/ign-gazebo/pull/466) + +1. Tape Measure Plugin + * [Pull Request 456](https://github.com/ignitionrobotics/ign-gazebo/pull/456) + +1. Move deselect and preview termination to render thread + * [Pull Request 493](https://github.com/ignitionrobotics/ign-gazebo/pull/493) + +1. Logical audio sensor plugin + * [Pull Request 401](https://github.com/ignitionrobotics/ign-gazebo/pull/401) + +1. add frame_id and child_frame_id attribute support for DiffDrive + * [Pull Request 361](https://github.com/ignitionrobotics/ign-gazebo/pull/361) + +1. Add ability to record video based on sim time + * [Pull Request 414](https://github.com/ignitionrobotics/ign-gazebo/pull/414) + +1. Add lockstep mode to video recording + * [Pull Request 419](https://github.com/ignitionrobotics/ign-gazebo/pull/419) + +1. Disable right click menu when using measuring tool + * [Pull Request 458](https://github.com/ignitionrobotics/ign-gazebo/pull/458) + ### Ignition Gazebo 3.5.0 (2020-11-03) 1. Updated source build instructions diff --git a/include/ignition/gazebo/System.hh b/include/ignition/gazebo/System.hh index fc2a3403c1..f8ef47ed01 100644 --- a/include/ignition/gazebo/System.hh +++ b/include/ignition/gazebo/System.hh @@ -44,21 +44,32 @@ namespace ignition /// will only operate on an Entity if it has all of the required /// Components. /// - /// Systems are executed in three phases: + /// Systems are executed in three phases, with each phase for a given step + /// corresponding to the entities at time UpdateInfo::simTime: /// * PreUpdate - /// * Has read-write access to world entities and components - /// * Executed with simulation time at (t0) + /// * Has read-write access to world entities and components. + /// * This is where systems say what they'd like to happen at time + /// UpdateInfo::simTime. /// * Can be used to modify state before physics runs, for example for /// applying control signals or performing network syncronization. /// * Update - /// * Has read-write access to world entities and components - /// * Responsible for propagating time from (t0) to (t0 + dt) - /// * Used for physics simulation step + /// * Has read-write access to world entities and components. + /// * Used for physics simulation step (i.e., simulates what happens at + /// time UpdateInfo::simTime). /// * PostUpdate - /// * Has read-only access to world entities and components - /// * Executed with simulation time at (t0 + dt) + /// * Has read-only access to world entities and components. + /// * Captures everything that happened at time UpdateInfo::simTime. /// * Used to read out results at the end of a simulation step to be used /// for sensor or controller updates. + /// + /// It's important to note that UpdateInfo::simTime does not refer to the + /// current time, but the time reached after the PreUpdate and Update calls + /// have finished. So, if any of the *Update functions are called with + /// simulation paused, time does not advance, which means the time reached + /// after PreUpdate and Update is the same as the starting time. This + /// explains why UpdateInfo::simTime is initially 0 if simulation is started + /// paused, while UpdateInfo::simTime is initially UpdateInfo::dt if + /// simulation is started un-paused. class IGNITION_GAZEBO_VISIBLE System { /// \brief Constructor diff --git a/include/ignition/gazebo/rendering/RenderUtil.hh b/include/ignition/gazebo/rendering/RenderUtil.hh index 36cb1ad63e..a30226419d 100644 --- a/include/ignition/gazebo/rendering/RenderUtil.hh +++ b/include/ignition/gazebo/rendering/RenderUtil.hh @@ -124,6 +124,11 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// Returns reference to the marker manager. public: class MarkerManager &MarkerManager(); + /// \brief Get simulation time that the current rendering state corresponds + /// to + /// \returns Simulation time. + public: std::chrono::steady_clock::duration SimTime() const; + /// \brief Set the entity being selected /// \param[in] _node Node representing the selected entity public: void SetSelectedEntity(const rendering::NodePtr &_node); diff --git a/src/EntityComponentManager_TEST.cc b/src/EntityComponentManager_TEST.cc index 9b72f1368d..5e03c68d79 100644 --- a/src/EntityComponentManager_TEST.cc +++ b/src/EntityComponentManager_TEST.cc @@ -2362,5 +2362,5 @@ TEST_P(EntityComponentManagerFixture, RemovedComponentsSyncBetweenServerAndGUI) // Run multiple times. We want to make sure that static globals don't cause // problems. -INSTANTIATE_TEST_CASE_P(EntityComponentManagerRepeat, +INSTANTIATE_TEST_SUITE_P(EntityComponentManagerRepeat, EntityComponentManagerFixture, ::testing::Range(1, 10)); diff --git a/src/Server_TEST.cc b/src/Server_TEST.cc index a6ff94dbdc..1f4e675850 100644 --- a/src/Server_TEST.cc +++ b/src/Server_TEST.cc @@ -995,4 +995,4 @@ TEST_P(ServerFixture, AddResourcePaths) // Run multiple times. We want to make sure that static globals don't cause // problems. -INSTANTIATE_TEST_CASE_P(ServerRepeat, ServerFixture, ::testing::Range(1, 2)); +INSTANTIATE_TEST_SUITE_P(ServerRepeat, ServerFixture, ::testing::Range(1, 2)); diff --git a/src/SimulationRunner_TEST.cc b/src/SimulationRunner_TEST.cc index 317d00aa9e..52795298b0 100644 --- a/src/SimulationRunner_TEST.cc +++ b/src/SimulationRunner_TEST.cc @@ -1294,5 +1294,5 @@ TEST_P(SimulationRunnerTest, GenerateWorldSdf) // Run multiple times. We want to make sure that static globals don't cause // problems. -INSTANTIATE_TEST_CASE_P(ServerRepeat, SimulationRunnerTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, SimulationRunnerTest, ::testing::Range(1, 2)); diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index a91f4821c4..3a41bbf814 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -19,8 +19,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -66,6 +68,11 @@ #include "ignition/gazebo/gui/GuiEvents.hh" #include "ignition/gazebo/rendering/RenderUtil.hh" +/// \brief condition variable for lockstepping video recording +/// todo(anyone) avoid using a global condition variable when we support +/// multiple viewports in the future. +std::condition_variable g_renderCv; + Q_DECLARE_METATYPE(std::string) namespace ignition @@ -198,6 +205,26 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \brief Path to save the recorded video public: std::string recordVideoSavePath; + /// \brief Use sim time as timestamp during video recording + /// By default (false), video encoding is done using real time. + public: bool recordVideoUseSimTime = false; + + /// \brief Lockstep gui with ECM when recording + public: bool recordVideoLockstep = false; + + /// \brief Video recorder bitrate (bps) + public: unsigned int recordVideoBitrate = 2070000; + + /// \brief Previous camera update time during video recording + /// only used in lockstep mode and recording in sim time. + public: std::chrono::steady_clock::time_point recordVideoUpdateTime; + + /// \brief Start tiem of video recording + public: std::chrono::steady_clock::time_point recordStartTime; + + /// \brief Camera pose publisher + public: transport::Node::Publisher recorderStatsPub; + /// \brief Target to move the user camera to public: std::string moveToTarget; @@ -237,6 +264,10 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// resource with the shapes plugin or not public: bool isPlacing = false; + /// \brief Atomic bool indicating whether the dropdown menu + /// is currently enabled or disabled. + public: std::atomic_bool dropdownMenuEnabled = true; + /// \brief The SDF string of the resource to be used with plugins that spawn /// entities. public: std::string spawnSdfString; @@ -340,6 +371,9 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \brief Render thread public : RenderThread *renderThread = nullptr; + //// \brief Set to true after the renderer is initialized + public: bool rendererInit = false; + //// \brief List of threads public: static QList threads; }; @@ -382,6 +416,19 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \brief Camera pose publisher public: transport::Node::Publisher cameraPosePub; + + /// \brief lockstep ECM updates with rendering + public: bool recordVideoLockstep = false; + + /// \brief True to indicate video recording in progress + public: bool recording = false; + + /// \brief mutex to protect the recording variable + public: std::mutex recordMutex; + + /// \brief mutex to protect the render condition variable + /// Used when recording in lockstep mode. + public: std::mutex renderMutex; }; } } @@ -397,6 +444,13 @@ IgnRenderer::IgnRenderer() : dataPtr(new IgnRendererPrivate) { this->dataPtr->moveToHelper.initCameraPose = this->cameraPose; + + // recorder stats topic + std::string recorderStatsTopic = "/gui/record_video/stats"; + this->dataPtr->recorderStatsPub = + this->dataPtr->node.Advertise(recorderStatsTopic); + ignmsg << "Video recorder stats topic advertised on [" + << recorderStatsTopic << "]" << std::endl; } @@ -465,7 +519,24 @@ void IgnRenderer::Render() } } + // check if recording is in lockstep mode and if it is using sim time + // if so, there is no need to update camera if sim time has not advanced + bool update = true; + if (this->dataPtr->recordVideoLockstep && + this->dataPtr->recordVideoUseSimTime && + this->dataPtr->videoEncoder.IsEncoding()) + { + std::chrono::steady_clock::time_point t = + std::chrono::steady_clock::time_point( + this->dataPtr->renderUtil.SimTime()); + if (t - this->dataPtr->recordVideoUpdateTime == std::chrono::seconds(0)) + update = false; + else + this->dataPtr->recordVideoUpdateTime = t; + } + // update and render to texture + if (update) { IGN_PROFILE("IgnRenderer::Render Update camera"); this->dataPtr->camera->Update(); @@ -489,14 +560,59 @@ void IgnRenderer::Render() if (this->dataPtr->videoEncoder.IsEncoding()) { this->dataPtr->camera->Copy(this->dataPtr->cameraImage); - this->dataPtr->videoEncoder.AddFrame( - this->dataPtr->cameraImage.Data(), width, height); + + std::chrono::steady_clock::time_point t = + std::chrono::steady_clock::now(); + if (this->dataPtr->recordVideoUseSimTime) + { + t = std::chrono::steady_clock::time_point( + this->dataPtr->renderUtil.SimTime()); + } + bool frameAdded = this->dataPtr->videoEncoder.AddFrame( + this->dataPtr->cameraImage.Data(), width, height, t); + + if (frameAdded) + { + // publish recorder stats + if (this->dataPtr->recordStartTime == + std::chrono::steady_clock::time_point( + std::chrono::duration(std::chrono::seconds(0)))) + { + // start time, i.e. time when first frame is added + this->dataPtr->recordStartTime = t; + } + + std::chrono::steady_clock::duration dt; + dt = t - this->dataPtr->recordStartTime; + int64_t sec, nsec; + std::tie(sec, nsec) = ignition::math::durationToSecNsec(dt); + msgs::Time msg; + msg.set_sec(sec); + msg.set_nsec(nsec); + this->dataPtr->recorderStatsPub.Publish(msg); + } } // Video recorder is idle. Start recording. else { + if (this->dataPtr->recordVideoUseSimTime) + ignmsg << "Recording video using sim time." << std::endl; + if (this->dataPtr->recordVideoLockstep) + { + ignmsg << "Recording video in lockstep mode" << std::endl; + if (!this->dataPtr->recordVideoUseSimTime) + { + ignwarn << "It is recommended to set to true " + << "when recording video in lockstep mode." << std::endl; + } + } + ignmsg << "Recording video using bitrate: " + << this->dataPtr->recordVideoBitrate << std::endl; this->dataPtr->videoEncoder.Start(this->dataPtr->recordVideoFormat, - this->dataPtr->recordVideoSavePath, width, height); + this->dataPtr->recordVideoSavePath, width, height, 25, + this->dataPtr->recordVideoBitrate); + this->dataPtr->recordStartTime = std::chrono::steady_clock::time_point( + std::chrono::duration(std::chrono::seconds(0))); } } else if (this->dataPtr->videoEncoder.IsEncoding()) @@ -694,6 +810,10 @@ void IgnRenderer::Render() ignition::gui::App()->findChild(), &event); } + + // only has an effect in video recording lockstep mode + // this notifes ECM to continue updating the scene + g_renderCv.notify_one(); } ///////////////////////////////////////////////// @@ -784,6 +904,7 @@ void IgnRenderer::HandleMouseEvent() std::lock_guard lock(this->dataPtr->mutex); this->BroadcastHoverPos(); this->BroadcastLeftClick(); + this->BroadcastRightClick(); this->HandleMouseContextMenu(); this->HandleModelPlacement(); this->HandleMouseTransformControl(); @@ -820,6 +941,26 @@ void IgnRenderer::BroadcastLeftClick() } } +///////////////////////////////////////////////// +void IgnRenderer::BroadcastRightClick() +{ + if (this->dataPtr->mouseEvent.Button() == common::MouseEvent::RIGHT && + this->dataPtr->mouseEvent.Type() == common::MouseEvent::RELEASE && + !this->dataPtr->mouseEvent.Dragging() && this->dataPtr->mouseDirty) + { + // If the dropdown menu is disabled, quash the mouse event + if (!this->dataPtr->dropdownMenuEnabled) + this->dataPtr->mouseDirty = false; + + math::Vector3d pos = this->ScreenToScene(this->dataPtr->mouseEvent.Pos()); + + ignition::gui::events::RightClickToScene rightClickToSceneEvent(pos); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &rightClickToSceneEvent); + } +} + ///////////////////////////////////////////////// void IgnRenderer::HandleMouseContextMenu() { @@ -1723,6 +1864,12 @@ void IgnRenderer::SetModelPath(const std::string &_filePath) this->dataPtr->spawnSdfPath = _filePath; } +///////////////////////////////////////////////// +void IgnRenderer::SetDropdownMenuEnabled(bool _enableDropdownMenu) +{ + this->dataPtr->dropdownMenuEnabled = _enableDropdownMenu; +} + ///////////////////////////////////////////////// void IgnRenderer::SetRecordVideo(bool _record, const std::string &_format, const std::string &_savePath) @@ -1733,6 +1880,27 @@ void IgnRenderer::SetRecordVideo(bool _record, const std::string &_format, this->dataPtr->recordVideoSavePath = _savePath; } +///////////////////////////////////////////////// +void IgnRenderer::SetRecordVideoUseSimTime(bool _useSimTime) +{ + std::lock_guard lock(this->dataPtr->mutex); + this->dataPtr->recordVideoUseSimTime = _useSimTime; +} + +///////////////////////////////////////////////// +void IgnRenderer::SetRecordVideoLockstep(bool _useSimTime) +{ + std::lock_guard lock(this->dataPtr->mutex); + this->dataPtr->recordVideoLockstep = _useSimTime; +} + +///////////////////////////////////////////////// +void IgnRenderer::SetRecordVideoBitrate(unsigned int _bitrate) +{ + std::lock_guard lock(this->dataPtr->mutex); + this->dataPtr->recordVideoBitrate = _bitrate; +} + ///////////////////////////////////////////////// void IgnRenderer::SetMoveTo(const std::string &_target) { @@ -2108,6 +2276,14 @@ void RenderWindowItem::Ready() this->dataPtr->renderThread->start(); this->update(); + + this->dataPtr->rendererInit = true; +} + +///////////////////////////////////////////////// +bool RenderWindowItem::RendererInitialized() const +{ + return this->dataPtr->rendererInit; } ///////////////////////////////////////////////// @@ -2350,6 +2526,52 @@ void Scene3D::LoadConfig(const tinyxml2::XMLElement *_pluginElem) } } + if (auto elem = _pluginElem->FirstChildElement("record_video")) + { + if (auto useSimTimeElem = elem->FirstChildElement("use_sim_time")) + { + bool useSimTime = false; + if (useSimTimeElem->QueryBoolText(&useSimTime) != tinyxml2::XML_SUCCESS) + { + ignerr << "Faild to parse value: " + << useSimTimeElem->GetText() << std::endl; + } + else + { + renderWindow->SetRecordVideoUseSimTime(useSimTime); + } + } + if (auto lockstepElem = elem->FirstChildElement("lockstep")) + { + bool lockstep = false; + if (lockstepElem->QueryBoolText(&lockstep) != tinyxml2::XML_SUCCESS) + { + ignerr << "Failed to parse value: " + << lockstepElem->GetText() << std::endl; + } + else + { + renderWindow->SetRecordVideoLockstep(lockstep); + } + } + if (auto bitrateElem = elem->FirstChildElement("bitrate")) + { + unsigned int bitrate = 0u; + std::stringstream bitrateStr; + bitrateStr << std::string(bitrateElem->GetText()); + bitrateStr >> bitrate; + if (bitrate > 0u) + { + renderWindow->SetRecordVideoBitrate(bitrate); + } + else + { + ignerr << "Video recorder bitrate must be larger than 0" + << std::endl; + } + } + } + if (auto elem = _pluginElem->FirstChildElement("fullscreen")) { auto fullscreen = false; @@ -2479,6 +2701,16 @@ void Scene3D::Update(const UpdateInfo &_info, this->dataPtr->cameraPosePub.Publish(poseMsg); } this->dataPtr->renderUtil->UpdateFromECM(_info, _ecm); + + // check if video recording is enabled and if we need to lock step + // ECM updates with GUI rendering during video recording + std::unique_lock lock(this->dataPtr->recordMutex); + if (this->dataPtr->recording && this->dataPtr->recordVideoLockstep && + renderWindow->RendererInitialized()) + { + std::unique_lock lock2(this->dataPtr->renderMutex); + g_renderCv.wait(lock2); + } } ///////////////////////////////////////////////// @@ -2502,6 +2734,9 @@ bool Scene3D::OnRecordVideo(const msgs::VideoRecord &_msg, renderWindow->SetRecordVideo(record, _msg.format(), _msg.save_filename()); _res.set_data(true); + + std::unique_lock lock(this->dataPtr->recordMutex); + this->dataPtr->recording = record; return true; } @@ -2730,6 +2965,18 @@ bool Scene3D::eventFilter(QObject *_obj, QEvent *_event) renderWindow->SetModelPath(spawnPreviewPathEvent->FilePath()); } } + else if (_event->type() == + ignition::gui::events::DropdownMenuEnabled::kType) + { + auto dropdownMenuEnabledEvent = + reinterpret_cast(_event); + if (dropdownMenuEnabledEvent) + { + auto renderWindow = this->PluginItem()->findChild(); + renderWindow->SetDropdownMenuEnabled( + dropdownMenuEnabledEvent->MenuEnabled()); + } + } // Standard event processing return QObject::eventFilter(_obj, _event); @@ -2761,6 +3008,13 @@ void RenderWindowItem::SetModelPath(const std::string &_filePath) this->dataPtr->renderThread->ignRenderer.SetModelPath(_filePath); } +///////////////////////////////////////////////// +void RenderWindowItem::SetDropdownMenuEnabled(bool _enableDropdownMenu) +{ + this->dataPtr->renderThread->ignRenderer.SetDropdownMenuEnabled( + _enableDropdownMenu); +} + ///////////////////////////////////////////////// void RenderWindowItem::SetRecordVideo(bool _record, const std::string &_format, const std::string &_savePath) @@ -2848,6 +3102,27 @@ void RenderWindowItem::SetWorldName(const std::string &_name) this->dataPtr->renderThread->ignRenderer.worldName = _name; } +///////////////////////////////////////////////// +void RenderWindowItem::SetRecordVideoUseSimTime(bool _useSimTime) +{ + this->dataPtr->renderThread->ignRenderer.SetRecordVideoUseSimTime( + _useSimTime); +} + +///////////////////////////////////////////////// +void RenderWindowItem::SetRecordVideoLockstep(bool _lockstep) +{ + this->dataPtr->renderThread->ignRenderer.SetRecordVideoLockstep( + _lockstep); +} + +///////////////////////////////////////////////// +void RenderWindowItem::SetRecordVideoBitrate(unsigned int _bitrate) +{ + this->dataPtr->renderThread->ignRenderer.SetRecordVideoBitrate( + _bitrate); +} + ///////////////////////////////////////////////// void RenderWindowItem::SetVisibilityMask(uint32_t _mask) { diff --git a/src/gui/plugins/scene3d/Scene3D.hh b/src/gui/plugins/scene3d/Scene3D.hh index 0947cffbc9..07143e40dd 100644 --- a/src/gui/plugins/scene3d/Scene3D.hh +++ b/src/gui/plugins/scene3d/Scene3D.hh @@ -199,6 +199,11 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \param[in] _filePath Sdf path of the model to load in for the user. public: void SetModelPath(const std::string &_filePath); + /// \brief Set if the dropdown menu is enabled or disabled. + /// \param[in] _enableDropdownMenu The boolean to enable or disable + /// the dropdown menu + public: void SetDropdownMenuEnabled(bool _enableDropdownMenu); + /// \brief Set whether to record video /// \param[in] _record True to start video recording, false to stop. /// \param[in] _format Video encoding format: "mp4", "ogv" @@ -206,6 +211,18 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { public: void SetRecordVideo(bool _record, const std::string &_format, const std::string &_savePath); + /// \brief Set whether to record video using sim time as timestamp + /// \param[in] _true True record video using sim time + public: void SetRecordVideoUseSimTime(bool _useSimTime); + + /// \brief Set whether to record video in lockstep mode + /// \param[in] _true True to record video in lockstep mode + public: void SetRecordVideoLockstep(bool _lockstep); + + /// \brief Set video recorder bitrate in bps + /// \param[in] _bitrate Bit rate to set to + public: void SetRecordVideoBitrate(unsigned int _bitrate); + /// \brief Move the user camera to move to the speficied target /// \param[in] _target Target to move the camera to public: void SetMoveTo(const std::string &_target); @@ -357,6 +374,9 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \brief Broadcasts a left click within the scene private: void BroadcastLeftClick(); + /// \brief Broadcasts a right click within the scene + private: void BroadcastRightClick(); + /// \brief Generate a unique entity id. /// \return The unique entity id private: Entity UniqueId(); @@ -521,6 +541,11 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \param[in] _filePath File path of the model to load in for the user. public: void SetModelPath(const std::string &_filePath); + /// \brief Set if the dropdown menu is enabled or disabled. + /// \param[in] _enableDropdownMenu The boolean to enable or disable + /// the menu + public: void SetDropdownMenuEnabled(bool _enableDropdownMenu); + /// \brief Set whether to record video /// \param[in] _record True to start video recording, false to stop. /// \param[in] _format Video encoding format: "mp4", "ogv" @@ -528,6 +553,18 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { public: void SetRecordVideo(bool _record, const std::string &_format, const std::string &_savePath); + /// \brief Set whether to record video using sim time as timestamp + /// \param[in] _true True record video using sim time + public: void SetRecordVideoUseSimTime(bool _useSimTime); + + /// \brief Set whether to record video in lockstep mode + /// \param[in] _true True to record video in lockstep mode + public: void SetRecordVideoLockstep(bool _lockstep); + + /// \brief Set video recorder bitrate in bps + /// \param[in] _bitrate Bit rate to set to + public: void SetRecordVideoBitrate(unsigned int _bitrate); + /// \brief Move the user camera to move to the specified target /// \param[in] _target Target to move the camera to public: void SetMoveTo(const std::string &_target); @@ -609,6 +646,12 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// the render window. public: void OnHovered(const ignition::math::Vector2i &_hoverPos); + /// \brief Get whether the renderer is initialized. The renderer is + /// initialized when the context is created and the render thread is + /// started. + /// \return True if the renderer is initialized. + public: bool RendererInitialized() const; + /// \brief Slot called when thread is ready to be started public Q_SLOTS: void Ready(); diff --git a/src/gui/plugins/tape_measure/TapeMeasure.cc b/src/gui/plugins/tape_measure/TapeMeasure.cc index adbec33d47..882ce7e9c3 100644 --- a/src/gui/plugins/tape_measure/TapeMeasure.cc +++ b/src/gui/plugins/tape_measure/TapeMeasure.cc @@ -127,6 +127,13 @@ void TapeMeasure::Measure() this->Reset(); this->dataPtr->measure = true; QGuiApplication::setOverrideCursor(Qt::CrossCursor); + + // Notify Scene3D to disable the right click menu while we use it to + // cancel our current measuring action + ignition::gui::events::DropdownMenuEnabled dropdownMenuEnabledEvent(false); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &dropdownMenuEnabledEvent); } ///////////////////////////////////////////////// @@ -149,6 +156,13 @@ void TapeMeasure::Reset() this->dataPtr->measure = false; this->newDistance(); QGuiApplication::restoreOverrideCursor(); + + // Notify Scene3D that we are done using the right click, so it can + // re-enable the settings menu + ignition::gui::events::DropdownMenuEnabled dropdownMenuEnabledEvent(true); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &dropdownMenuEnabledEvent); } ///////////////////////////////////////////////// @@ -271,6 +285,15 @@ bool TapeMeasure::eventFilter(QObject *_obj, QEvent *_event) this->dataPtr->startPoint.Distance(this->dataPtr->endPoint); this->newDistance(); QGuiApplication::restoreOverrideCursor(); + + // Notify Scene3D that we are done using the right click, so it can + // re-enable the settings menu + ignition::gui::events::DropdownMenuEnabled + dropdownMenuEnabledEvent(true); + + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &dropdownMenuEnabledEvent); } this->dataPtr->currentId = this->dataPtr->kEndPointId; } @@ -293,6 +316,15 @@ bool TapeMeasure::eventFilter(QObject *_obj, QEvent *_event) this->Reset(); } } + // Cancel the current action if a right click is detected + else if (_event->type() == ignition::gui::events::RightClickToScene::kType) + { + if (this->dataPtr->measure) + { + this->Reset(); + } + } + return QObject::eventFilter(_obj, _event); } diff --git a/src/rendering/RenderUtil.cc b/src/rendering/RenderUtil.cc index 710862c326..acf90e1347 100644 --- a/src/rendering/RenderUtil.cc +++ b/src/rendering/RenderUtil.cc @@ -1349,6 +1349,13 @@ MarkerManager &RenderUtil::MarkerManager() return this->dataPtr->markerManager; } +////////////////////////////////////////////////// +std::chrono::steady_clock::duration RenderUtil::SimTime() const +{ + std::lock_guard lock(this->dataPtr->updateMutex); + return this->dataPtr->simTime; +} + ///////////////////////////////////////////////// void RenderUtil::SetSelectedEntity(const rendering::NodePtr &_node) { diff --git a/src/systems/diff_drive/DiffDrive.cc b/src/systems/diff_drive/DiffDrive.cc index 1686beebcd..917d65bf15 100644 --- a/src/systems/diff_drive/DiffDrive.cc +++ b/src/systems/diff_drive/DiffDrive.cc @@ -138,6 +138,12 @@ class ignition::gazebo::systems::DiffDrivePrivate /// \brief A mutex to protect the target velocity command. public: std::mutex mutex; + + /// \brief frame_id from sdf. + public: std::string sdfFrameId; + + /// \brief child_frame_id from sdf. + public: std::string sdfChildFrameId; }; ////////////////////////////////////////////////// @@ -277,6 +283,12 @@ void DiffDrive::Configure(const Entity &_entity, this->dataPtr->odomPub = this->dataPtr->node.Advertise( odomTopic); + if (_sdf->HasElement("frame_id")) + this->dataPtr->sdfFrameId = _sdf->Get("frame_id"); + + if (_sdf->HasElement("child_frame_id")) + this->dataPtr->sdfChildFrameId = _sdf->Get("child_frame_id"); + ignmsg << "DiffDrive subscribing to twist messages on [" << topic << "]" << std::endl; } @@ -468,16 +480,33 @@ void DiffDrivePrivate::UpdateOdometry(const ignition::gazebo::UpdateInfo &_info, // Set the frame id. auto frame = msg.mutable_header()->add_data(); frame->set_key("frame_id"); - frame->add_value(this->model.Name(_ecm) + "/odom"); + if (this->sdfFrameId.empty()) + { + frame->add_value(this->model.Name(_ecm) + "/odom"); + } + else + { + frame->add_value(this->sdfFrameId); + } std::optional linkName = this->canonicalLink.Name(_ecm); - if (linkName) + if (this->sdfChildFrameId.empty()) + { + if (linkName) + { + auto childFrame = msg.mutable_header()->add_data(); + childFrame->set_key("child_frame_id"); + childFrame->add_value(this->model.Name(_ecm) + "/" + *linkName); + } + } + else { auto childFrame = msg.mutable_header()->add_data(); childFrame->set_key("child_frame_id"); - childFrame->add_value(this->model.Name(_ecm) + "/" + *linkName); + childFrame->add_value(this->sdfChildFrameId); } + // Publish the message this->odomPub.Publish(msg); } diff --git a/src/systems/scene_broadcaster/SceneBroadcaster.cc b/src/systems/scene_broadcaster/SceneBroadcaster.cc index 0918c756bb..7e5094cc0d 100644 --- a/src/systems/scene_broadcaster/SceneBroadcaster.cc +++ b/src/systems/scene_broadcaster/SceneBroadcaster.cc @@ -226,6 +226,11 @@ void SceneBroadcaster::Configure( auto readHertz = _sdf->Get("dynamic_pose_hertz", 60); this->dataPtr->dyPoseHertz = readHertz.first; + auto stateHerz = _sdf->Get("state_hertz", 60); + this->dataPtr->statePublishPeriod = + std::chrono::duration>( + std::chrono::milliseconds(1000/stateHerz.first)); + // Add to graph { std::lock_guard lock(this->dataPtr->graphMutex); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c506039bc6..86cdb3578d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,6 +11,7 @@ configure_file (test_config.hh.in ${PROJECT_BINARY_DIR}/include/ignition/gazebo/ add_library(gtest STATIC gtest/src/gtest-all.cc) add_library(gtest_main STATIC gtest/src/gtest_main.cc) target_link_libraries(gtest_main gtest) +target_compile_features(gtest PUBLIC cxx_std_11) set(GTEST_LIBRARY "${PROJECT_BINARY_DIR}/test/libgtest.a") set(GTEST_MAIN_LIBRARY "${PROJECT_BINARY_DIR}/test/libgtest_main.a") diff --git a/test/gtest/cmake/Config.cmake.in b/test/gtest/cmake/Config.cmake.in new file mode 100644 index 0000000000..12be4498b1 --- /dev/null +++ b/test/gtest/cmake/Config.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ +include(CMakeFindDependencyMacro) +if (@GTEST_HAS_PTHREAD@) + set(THREADS_PREFER_PTHREAD_FLAG @THREADS_PREFER_PTHREAD_FLAG@) + find_dependency(Threads) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") +check_required_components("@project_name@") diff --git a/test/gtest/cmake/gtest.pc.in b/test/gtest/cmake/gtest.pc.in new file mode 100644 index 0000000000..9aae29e267 --- /dev/null +++ b/test/gtest/cmake/gtest.pc.in @@ -0,0 +1,10 @@ +prefix=${pcfiledir}/../.. +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: gtest +Description: GoogleTest (without main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Libs: -L${libdir} -lgtest @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ @CMAKE_THREAD_LIBS_INIT@ diff --git a/test/gtest/cmake/gtest_main.pc.in b/test/gtest/cmake/gtest_main.pc.in new file mode 100644 index 0000000000..915f2973af --- /dev/null +++ b/test/gtest/cmake/gtest_main.pc.in @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: gtest_main +Description: GoogleTest (with main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Requires: gtest +Libs: -L${libdir} -lgtest_main @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ @CMAKE_THREAD_LIBS_INIT@ diff --git a/test/gtest/cmake/internal_utils.cmake b/test/gtest/cmake/internal_utils.cmake index 8cb21894ce..2f70f0b084 100644 --- a/test/gtest/cmake/internal_utils.cmake +++ b/test/gtest/cmake/internal_utils.cmake @@ -12,6 +12,10 @@ # Test and Google Mock's option() definitions, and thus must be # called *after* the options have been defined. +if (POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +endif (POLICY CMP0054) + # Tweaks CMake's default compiler/linker settings to suit Google Test's needs. # # This must be a macro(), as inside a function string() can only @@ -20,8 +24,10 @@ macro(fix_default_compiler_settings_) if (MSVC) # For MSVC, CMake sets certain flags to defaults we want to override. # This replacement code is taken from sample in the CMake Wiki at - # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace. + # https://gitlab.kitware.com/cmake/community/wikis/FAQ#dynamic-replace. foreach (flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt) @@ -37,7 +43,12 @@ macro(fix_default_compiler_settings_) # We prefer more strict warning checking for building Google Test. # Replaces /W3 with /W4 in defaults. - string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}") + string(REPLACE "/W3" "/W4" ${flag_var} "${${flag_var}}") + + # Prevent D9025 warning for targets that have exception handling + # turned off (/EHs-c- flag). Where required, exceptions are explicitly + # re-enabled using the cxx_exception_flags variable. + string(REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}") endforeach() endif() endmacro() @@ -46,33 +57,41 @@ endmacro() # Google Mock. You can tweak these definitions to suit your need. A # variable's value is empty before it's explicitly assigned to. macro(config_compiler_and_linker) - if (NOT gtest_disable_pthreads) + # Note: pthreads on MinGW is not supported, even if available + # instead, we use windows threading primitives + unset(GTEST_HAS_PTHREAD) + if (NOT gtest_disable_pthreads AND NOT MINGW) # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. find_package(Threads) + if (CMAKE_USE_PTHREADS_INIT) + set(GTEST_HAS_PTHREAD ON) + endif() endif() fix_default_compiler_settings_() if (MSVC) # Newlines inside flags variables break CMake's NMake generator. # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. - set(cxx_base_flags "-GS -W4 -WX -wd4127 -wd4251 -wd4275 -nologo -J -Zi") - if (MSVC_VERSION LESS 1400) - # Suppress spurious warnings MSVC 7.1 sometimes issues. - # Forcing value to bool. - set(cxx_base_flags "${cxx_base_flags} -wd4800") - # Copy constructor and assignment operator could not be generated. - set(cxx_base_flags "${cxx_base_flags} -wd4511 -wd4512") - # Compatibility warnings not applicable to Google Test. - # Resolved overload was found by argument-dependent lookup. - set(cxx_base_flags "${cxx_base_flags} -wd4675") - endif() + set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J -Zi") set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32") set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN") set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") - set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0") + set(cxx_no_exception_flags "-EHs-c- -D_HAS_EXCEPTIONS=0") set(cxx_no_rtti_flags "-GR-") + # Suppress "unreachable code" warning + # http://stackoverflow.com/questions/3232669 explains the issue. + set(cxx_base_flags "${cxx_base_flags} -wd4702") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(cxx_base_flags "-Wall -Wshadow -Werror -Wconversion") + set(cxx_exception_flags "-fexceptions") + set(cxx_no_exception_flags "-fno-exceptions") + set(cxx_strict_flags "-W -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wunused-parameter -Wcast-align -Wchar-subscripts -Winline -Wredundant-decls") + set(cxx_no_rtti_flags "-fno-rtti") elseif (CMAKE_COMPILER_IS_GNUCXX) - set(cxx_base_flags "-Wall -Wshadow") + set(cxx_base_flags "-Wall -Wshadow -Werror") + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0) + set(cxx_base_flags "${cxx_base_flags} -Wno-error=dangling-else") + endif() set(cxx_exception_flags "-fexceptions") set(cxx_no_exception_flags "-fno-exceptions") # Until version 4.3.2, GCC doesn't define a macro to indicate @@ -104,19 +123,20 @@ macro(config_compiler_and_linker) set(cxx_no_rtti_flags "") endif() - if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed. - set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") + # The pthreads library is available and allowed? + if (DEFINED GTEST_HAS_PTHREAD) + set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=1") else() - set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0") + set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=0") endif() + set(cxx_base_flags "${cxx_base_flags} ${GTEST_HAS_PTHREAD_MACRO}") # For building gtest's own tests and samples. - set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}") + set(cxx_exception "${cxx_base_flags} ${cxx_exception_flags}") set(cxx_no_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}") set(cxx_default "${cxx_exception}") set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}") - set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1") # For building the gtest libraries. set(cxx_strict "${cxx_default} ${cxx_strict_flags}") @@ -131,13 +151,42 @@ function(cxx_library_with_type name type cxx_flags) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") + # Generate debug library name with a postfix. + set_target_properties(${name} + PROPERTIES + DEBUG_POSTFIX "d") + # Set the output directory for build artifacts + set_target_properties(${name} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + # make PDBs match library name + get_target_property(pdb_debug_postfix ${name} DEBUG_POSTFIX) + set_target_properties(${name} + PROPERTIES + PDB_NAME "${name}" + PDB_NAME_DEBUG "${name}${pdb_debug_postfix}" + COMPILE_PDB_NAME "${name}" + COMPILE_PDB_NAME_DEBUG "${name}${pdb_debug_postfix}") + if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") set_target_properties(${name} PROPERTIES COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") + if (NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + target_compile_definitions(${name} INTERFACE + $) + endif() endif() - if (CMAKE_USE_PTHREADS_INIT) - target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) + if (DEFINED GTEST_HAS_PTHREAD) + if ("${CMAKE_VERSION}" VERSION_LESS "3.1.0") + set(threads_spec ${CMAKE_THREAD_LIBS_INIT}) + else() + set(threads_spec Threads::Threads) + endif() + target_link_libraries(${name} PUBLIC ${threads_spec}) endif() endfunction() @@ -159,6 +208,10 @@ endfunction() # is built from the given source files with the given compiler flags. function(cxx_executable_with_flags name cxx_flags libs) add_executable(${name} ${ARGN}) + if (MSVC) + # BigObj required for tests. + set(cxx_flags "${cxx_flags} -bigobj") + endif() if (cxx_flags) set_target_properties(${name} PROPERTIES @@ -195,7 +248,13 @@ find_package(PythonInterp) # from the given source files with the given compiler flags. function(cxx_test_with_flags name cxx_flags libs) cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) - add_test(${name} ${name}) + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND "powershell" "-Command" "${CMAKE_CURRENT_BINARY_DIR}/$/RunTest.ps1" "$") + else() + add_test(NAME ${name} + COMMAND "$") + endif() endfunction() # cxx_test(name libs srcs...) @@ -213,15 +272,87 @@ endfunction() # creates a Python test with the given name whose main module is in # test/name.py. It does nothing if Python is not installed. function(py_test name) - # We are not supporting Python tests on Linux yet as they consider - # all Linux environments to be google3 and try to use google3 features. if (PYTHONINTERP_FOUND) - # ${CMAKE_BINARY_DIR} is known at configuration time, so we can - # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known - # only at ctest runtime (by calling ctest -c ), so - # we have to escape $ to delay variable substitution here. - add_test(${name} - ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py - --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE}) + if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 3.1) + if (CMAKE_CONFIGURATION_TYPES) + # Multi-configuration build generators as for Visual Studio save + # output in a subdirectory of CMAKE_CURRENT_BINARY_DIR (Debug, + # Release etc.), so we have to provide it here. + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND powershell -Command ${CMAKE_CURRENT_BINARY_DIR}/$/RunTest.ps1 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/$ ${ARGN}) + else() + add_test(NAME ${name} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/$ ${ARGN}) + endif() + else (CMAKE_CONFIGURATION_TYPES) + # Single-configuration build generators like Makefile generators + # don't have subdirs below CMAKE_CURRENT_BINARY_DIR. + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND powershell -Command ${CMAKE_CURRENT_BINARY_DIR}/RunTest.ps1 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR} ${ARGN}) + else() + add_test(NAME ${name} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR} ${ARGN}) + endif() + endif (CMAKE_CONFIGURATION_TYPES) + else() + # ${CMAKE_CURRENT_BINARY_DIR} is known at configuration time, so we can + # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known + # only at ctest runtime (by calling ctest -c ), so + # we have to escape $ to delay variable substitution here. + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND powershell -Command ${CMAKE_CURRENT_BINARY_DIR}/RunTest.ps1 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE} ${ARGN}) + else() + add_test(NAME ${name} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE} ${ARGN}) + endif() + endif() + endif(PYTHONINTERP_FOUND) +endfunction() + +# install_project(targets...) +# +# Installs the specified targets and configures the associated pkgconfig files. +function(install_project) + if(INSTALL_GTEST) + install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + # Install the project targets. + install(TARGETS ${ARGN} + EXPORT ${targets_export_name} + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + # Install PDBs + foreach(t ${ARGN}) + get_target_property(t_pdb_name ${t} COMPILE_PDB_NAME) + get_target_property(t_pdb_name_debug ${t} COMPILE_PDB_NAME_DEBUG) + get_target_property(t_pdb_output_directory ${t} PDB_OUTPUT_DIRECTORY) + install(FILES + "${t_pdb_output_directory}/\${CMAKE_INSTALL_CONFIG_NAME}/$<$:${t_pdb_name_debug}>$<$>:${t_pdb_name}>.pdb" + DESTINATION ${CMAKE_INSTALL_LIBDIR} + OPTIONAL) + endforeach() + endif() + # Configure and install pkgconfig files. + foreach(t ${ARGN}) + set(configured_pc "${generated_dir}/${t}.pc") + configure_file("${PROJECT_SOURCE_DIR}/cmake/${t}.pc.in" + "${configured_pc}" @ONLY) + install(FILES "${configured_pc}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + endforeach() endif() endfunction() diff --git a/test/gtest/cmake/libgtest.la.in b/test/gtest/cmake/libgtest.la.in new file mode 100644 index 0000000000..840c83885f --- /dev/null +++ b/test/gtest/cmake/libgtest.la.in @@ -0,0 +1,21 @@ +# libgtest.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.6 + +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Names of this library. +library_names='libgtest.so' + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='@CMAKE_INSTALL_FULL_LIBDIR@' diff --git a/test/gtest/gtest-1.10.0.diff b/test/gtest/gtest-1.10.0.diff new file mode 100644 index 0000000000..9df3ab2100 --- /dev/null +++ b/test/gtest/gtest-1.10.0.diff @@ -0,0 +1,15 @@ +diff --git a/test/gtest/src/gtest.cc b/test/gtest/src/gtest.cc +index a5b4e5a..1dff1a6 100644 +--- a/test/gtest/src/gtest.cc ++++ b/test/gtest/src/gtest.cc +@@ -34,6 +34,10 @@ + #include "gtest/internal/custom/gtest.h" + #include "gtest/gtest-spi.h" + ++#ifndef _WIN32 ++#pragma GCC system_header ++#endif ++ + #include + #include + #include diff --git a/test/gtest/gtest-1.7.0.diff b/test/gtest/gtest-1.7.0.diff deleted file mode 100644 index e8783960fc..0000000000 --- a/test/gtest/gtest-1.7.0.diff +++ /dev/null @@ -1,44 +0,0 @@ -diff -r a5e72dd0ecf3 test/gtest/include/gtest/gtest-typed-test.h ---- a/test/gtest/include/gtest/gtest-typed-test.h Mon Nov 04 11:47:43 2013 -0800 -+++ b/test/gtest/include/gtest/gtest-typed-test.h Mon Nov 04 11:49:12 2013 -0800 -@@ -31,6 +31,7 @@ - - #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ - #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ -+#pragma GCC system_header - - // This header implements typed tests and type-parameterized tests. - -diff -r a5e72dd0ecf3 test/gtest/src/gtest.cc ---- a/test/gtest/src/gtest.cc Mon Nov 04 11:47:43 2013 -0800 -+++ b/test/gtest/src/gtest.cc Mon Nov 04 11:49:12 2013 -0800 -@@ -33,6 +33,7 @@ - - #include "gtest/gtest.h" - #include "gtest/gtest-spi.h" -+#pragma GCC system_header - - #include - #include -diff -r c33b44f8a9a1 test/gtest/include/gtest/internal/gtest-port.h ---- a/test/gtest/include/gtest/internal/gtest-port.h Wed Nov 06 11:23:38 2013 -0800 -+++ b/test/gtest/include/gtest/internal/gtest-port.h Wed Nov 06 17:12:57 2013 -0800 -@@ -39,6 +39,7 @@ - - #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ - #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -+#pragma GCC system_header - - // The user can define the following macros in the build script to - // control Google Test's behavior. If the user doesn't define a macro -diff -r e980730656c1 test/gtest/include/gtest/gtest-printers.h ---- a/test/gtest/include/gtest/gtest-printers.h Wed Nov 06 17:13:57 2013 -0800 -+++ b/test/gtest/include/gtest/gtest-printers.h Thu Nov 07 09:29:28 2013 -0800 -@@ -94,6 +94,7 @@ - - #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ - #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ -+#pragma GCC system_header - - #include // NOLINT - #include diff --git a/test/gtest/include/gtest/gtest-death-test.h b/test/gtest/include/gtest/gtest-death-test.h index 957a69c6a9..dc878ffbb3 100644 --- a/test/gtest/include/gtest/gtest-death-test.h +++ b/test/gtest/include/gtest/gtest-death-test.h @@ -26,14 +26,14 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ @@ -99,10 +99,11 @@ GTEST_API_ bool InDeathTestChild(); // // On the regular expressions used in death tests: // +// GOOGLETEST_CM0005 DO NOT DELETE // On POSIX-compliant systems (*nix), we use the library, // which uses the POSIX extended regex syntax. // -// On other platforms (e.g. Windows), we only support a simple regex +// On other platforms (e.g. Windows or Mac), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE @@ -160,7 +161,6 @@ GTEST_API_ bool InDeathTestChild(); // is rarely a problem as people usually don't put the test binary // directory in PATH. // -// TODO(wan@google.com): make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output @@ -169,7 +169,7 @@ GTEST_API_ bool InDeathTestChild(); GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) // Like ASSERT_EXIT, but continues on to successive tests in the -// test case, if any: +// test suite, if any: # define EXPECT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) @@ -180,7 +180,7 @@ GTEST_API_ bool InDeathTestChild(); ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Like ASSERT_DEATH, but continues on to successive tests in the -// test case, if any: +// test suite, if any: # define EXPECT_DEATH(statement, regex) \ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) @@ -198,9 +198,10 @@ class GTEST_API_ ExitedWithCode { const int exit_code_; }; -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Tests that an exit code describes an exit due to termination by a // given signal. +// GOOGLETEST_CM0006 DO NOT DELETE class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); @@ -226,7 +227,7 @@ class GTEST_API_ KilledBySignal { // return 12; // } // -// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) { // int sideeffect = 0; // // Only asserts in dbg. // EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); @@ -272,6 +273,54 @@ class GTEST_API_ KilledBySignal { # endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters +// on systems that support death tests. This allows one to write such a macro on +// a system that does not support death tests and be sure that it will compile +// on a death-test supporting system. It is exposed publicly so that systems +// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST +// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and +// ASSERT_DEATH_IF_SUPPORTED. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter if and only if EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is @@ -284,9 +333,9 @@ class GTEST_API_ KilledBySignal { ASSERT_DEATH(statement, regex) #else # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return) #endif } // namespace testing diff --git a/test/gtest/include/gtest/gtest-matchers.h b/test/gtest/include/gtest/gtest-matchers.h new file mode 100644 index 0000000000..9de6c2e10a --- /dev/null +++ b/test/gtest/include/gtest/gtest-matchers.h @@ -0,0 +1,750 @@ +// Copyright 2007, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +// IWYU pragma: private, include "testing/base/public/gunit.h" +// IWYU pragma: friend third_party/googletest/googlemock/.* +// IWYU pragma: friend third_party/googletest/googletest/.* + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ + +#include +#include +#include +#include + +#include "gtest/gtest-printers.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +// MSVC warning C5046 is new as of VS2017 version 15.8. +#if defined(_MSC_VER) && _MSC_VER >= 1915 +#define GTEST_MAYBE_5046_ 5046 +#else +#define GTEST_MAYBE_5046_ +#endif + +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by + clients of class B */ + /* Symbol involving type with internal linkage not defined */) + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherImpl that implements the +// MatcherInterface interface, and +// 2. a factory function that creates a Matcher object from a +// FooMatcherImpl*. +// +// The two-level delegation design makes it possible to allow a user +// to write "v" instead of "Eq(v)" where a Matcher is expected, which +// is impossible if we pass matchers by pointers. It also eases +// ownership management as Matcher objects can now be copied like +// plain values. + +// MatchResultListener is an abstract class. Its << operator can be +// used by a matcher to explain why a value matches or doesn't match. +// +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream, and does not dereference it + // in the constructor or destructor. + explicit MatchResultListener(::std::ostream* os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x) { + if (stream_ != nullptr) *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream* stream() { return stream_; } + + // Returns true if and only if the listener is interested in an explanation + // of the match result. A matcher's MatchAndExplain() method can use + // this information to avoid generating the explanation when no one + // intends to hear it. + bool IsInterested() const { return stream_ != nullptr; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + +// An instance of a subclass of this knows how to describe itself as a +// matcher. +class MatcherDescriberInterface { + public: + virtual ~MatcherDescriberInterface() {} + + // Describes this matcher to an ostream. The function should print + // a verb phrase that describes the property a value matching this + // matcher should have. The subject of the verb phrase is the value + // being matched. For example, the DescribeTo() method of the Gt(7) + // matcher prints "is greater than 7". + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. For + // example, if the description of this matcher is "is greater than + // 7", the negated description could be "is not greater than 7". + // You are not required to override this when implementing + // MatcherInterface, but it is highly advised so that your matcher + // can produce good error messages. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; + } +}; + +// The implementation of a matcher. +template +class MatcherInterface : public MatcherDescriberInterface { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener' if necessary (see the next paragraph), in + // the form of a non-restrictive relative clause ("which ...", + // "whose ...", etc) that describes x. For example, the + // MatchAndExplain() method of the Pointee(...) matcher should + // generate an explanation like "which points to ...". + // + // Implementations of MatchAndExplain() should add an explanation of + // the match result *if and only if* they can provide additional + // information that's not already present (or not obvious) in the + // print-out of x and the matcher's description. Whether the match + // succeeds is not a factor in deciding whether an explanation is + // needed, as sometimes the caller needs to print a failure message + // when the match succeeds (e.g. when the matcher is used inside + // Not()). + // + // For example, a "has at least 10 elements" matcher should explain + // what the actual element count is, regardless of the match result, + // as it is useful information to the reader; on the other hand, an + // "is empty" matcher probably only needs to explain what the actual + // size is when the match fails, as it's redundant to say that the + // size is 0 when the value is already known to be empty. + // + // You should override this method when defining a new matcher. + // + // It's the responsibility of the caller (Google Test) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Inherits these methods from MatcherDescriberInterface: + // virtual void DescribeTo(::std::ostream* os) const = 0; + // virtual void DescribeNegationTo(::std::ostream* os) const; +}; + +namespace internal { + +// Converts a MatcherInterface to a MatcherInterface. +template +class MatcherInterfaceAdapter : public MatcherInterface { + public: + explicit MatcherInterfaceAdapter(const MatcherInterface* impl) + : impl_(impl) {} + ~MatcherInterfaceAdapter() override { delete impl_; } + + void DescribeTo(::std::ostream* os) const override { impl_->DescribeTo(os); } + + void DescribeNegationTo(::std::ostream* os) const override { + impl_->DescribeNegationTo(os); + } + + bool MatchAndExplain(const T& x, + MatchResultListener* listener) const override { + return impl_->MatchAndExplain(x, listener); + } + + private: + const MatcherInterface* const impl_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter); +}; + +struct AnyEq { + template + bool operator()(const A& a, const B& b) const { return a == b; } +}; +struct AnyNe { + template + bool operator()(const A& a, const B& b) const { return a != b; } +}; +struct AnyLt { + template + bool operator()(const A& a, const B& b) const { return a < b; } +}; +struct AnyGt { + template + bool operator()(const A& a, const B& b) const { return a > b; } +}; +struct AnyLe { + template + bool operator()(const A& a, const B& b) const { return a <= b; } +}; +struct AnyGe { + template + bool operator()(const A& a, const B& b) const { return a >= b; } +}; + +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(nullptr) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream* os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +// An internal class for implementing Matcher, which will derive +// from it. We put functionalities common to all Matcher +// specializations here to avoid code duplication. +template +class MatcherBase { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener'. + bool MatchAndExplain(const T& x, MatchResultListener* listener) const { + return impl_->MatchAndExplain(x, listener); + } + + // Returns true if and only if this matcher matches x. + bool Matches(const T& x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } + + // Describes this matcher to an ostream. + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the negation of this matcher to an ostream. + void DescribeNegationTo(::std::ostream* os) const { + impl_->DescribeNegationTo(os); + } + + // Explains why x matches, or doesn't match, the matcher. + void ExplainMatchResultTo(const T& x, ::std::ostream* os) const { + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); + } + + // Returns the describer for this matcher object; retains ownership + // of the describer, which is only guaranteed to be alive when + // this matcher object is alive. + const MatcherDescriberInterface* GetDescriber() const { + return impl_.get(); + } + + protected: + MatcherBase() {} + + // Constructs a matcher from its implementation. + explicit MatcherBase(const MatcherInterface* impl) : impl_(impl) {} + + template + explicit MatcherBase( + const MatcherInterface* impl, + typename std::enable_if::value>::type* = + nullptr) + : impl_(new internal::MatcherInterfaceAdapter(impl)) {} + + MatcherBase(const MatcherBase&) = default; + MatcherBase& operator=(const MatcherBase&) = default; + MatcherBase(MatcherBase&&) = default; + MatcherBase& operator=(MatcherBase&&) = default; + + virtual ~MatcherBase() {} + + private: + std::shared_ptr> impl_; +}; + +} // namespace internal + +// A Matcher is a copyable and IMMUTABLE (except by assignment) +// object that can check whether a value of type T matches. The +// implementation of Matcher is just a std::shared_ptr to const +// MatcherInterface. Don't inherit from Matcher! +template +class Matcher : public internal::MatcherBase { + public: + // Constructs a null matcher. Needed for storing Matcher objects in STL + // containers. A default-constructed matcher is not yet initialized. You + // cannot use it until a valid value has been assigned to it. + explicit Matcher() {} // NOLINT + + // Constructs a matcher from its implementation. + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template + explicit Matcher( + const MatcherInterface* impl, + typename std::enable_if::value>::type* = + nullptr) + : internal::MatcherBase(impl) {} + + // Implicit constructor here allows people to write + // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes + Matcher(T value); // NOLINT +}; + +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +#if GTEST_HAS_ABSL +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views directly. + Matcher(absl::string_view s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views directly. + Matcher(absl::string_view s); // NOLINT +}; +#endif // GTEST_HAS_ABSL + +// Prints a matcher in a human-readable format. +template +std::ostream& operator<<(std::ostream& os, const Matcher& matcher) { + matcher.DescribeTo(&os); + return os; +} + +// The PolymorphicMatcher class template makes it easy to implement a +// polymorphic matcher (i.e. a matcher that can match values of more +// than one type, e.g. Eq(n) and NotNull()). +// +// To define a polymorphic matcher, a user should provide an Impl +// class that has a DescribeTo() method and a DescribeNegationTo() +// method, and define a member function (or member function template) +// +// bool MatchAndExplain(const Value& value, +// MatchResultListener* listener) const; +// +// See the definition of NotNull() for a complete example. +template +class PolymorphicMatcher { + public: + explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} + + // Returns a mutable reference to the underlying matcher + // implementation object. + Impl& mutable_impl() { return impl_; } + + // Returns an immutable reference to the underlying matcher + // implementation object. + const Impl& impl() const { return impl_; } + + template + operator Matcher() const { + return Matcher(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public MatcherInterface { + public: + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); } + + virtual void DescribeNegationTo(::std::ostream* os) const { + impl_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_.MatchAndExplain(x, listener); + } + + private: + const Impl impl_; + }; + + Impl impl_; +}; + +// Creates a matcher from its implementation. +// DEPRECATED: Especially in the generic code, prefer: +// Matcher(new MyMatcherImpl(...)); +// +// MakeMatcher may create a Matcher that accepts its argument by value, which +// leads to unnecessary copies & lack of support for non-copyable types. +template +inline Matcher MakeMatcher(const MatcherInterface* impl) { + return Matcher(impl); +} + +// Creates a polymorphic matcher from its implementation. This is +// easier to use than the PolymorphicMatcher constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicMatcher(foo); +// vs +// PolymorphicMatcher(foo); +template +inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { + return PolymorphicMatcher(impl); +} + +namespace internal { +// Implements a matcher that compares a given value with a +// pre-supplied value using one of the ==, <=, <, etc, operators. The +// two values being compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq(5) can be +// used to match an int, a short, a double, etc). Therefore we use +// a template type conversion operator in the implementation. +// +// The following template definition assumes that the Rhs parameter is +// a "bare" type (i.e. neither 'const T' nor 'T&'). +template +class ComparisonBase { + public: + explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} + template + operator Matcher() const { + return Matcher(new Impl(rhs_)); + } + + private: + template + static const T& Unwrap(const T& v) { return v; } + template + static const T& Unwrap(std::reference_wrapper v) { return v; } + + template + class Impl : public MatcherInterface { + public: + explicit Impl(const Rhs& rhs) : rhs_(rhs) {} + bool MatchAndExplain(Lhs lhs, + MatchResultListener* /* listener */) const override { + return Op()(lhs, Unwrap(rhs_)); + } + void DescribeTo(::std::ostream* os) const override { + *os << D::Desc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + void DescribeNegationTo(::std::ostream* os) const override { + *os << D::NegatedDesc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + + private: + Rhs rhs_; + }; + Rhs rhs_; +}; + +template +class EqMatcher : public ComparisonBase, Rhs, AnyEq> { + public: + explicit EqMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyEq>(rhs) { } + static const char* Desc() { return "is equal to"; } + static const char* NegatedDesc() { return "isn't equal to"; } +}; +template +class NeMatcher : public ComparisonBase, Rhs, AnyNe> { + public: + explicit NeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyNe>(rhs) { } + static const char* Desc() { return "isn't equal to"; } + static const char* NegatedDesc() { return "is equal to"; } +}; +template +class LtMatcher : public ComparisonBase, Rhs, AnyLt> { + public: + explicit LtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLt>(rhs) { } + static const char* Desc() { return "is <"; } + static const char* NegatedDesc() { return "isn't <"; } +}; +template +class GtMatcher : public ComparisonBase, Rhs, AnyGt> { + public: + explicit GtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGt>(rhs) { } + static const char* Desc() { return "is >"; } + static const char* NegatedDesc() { return "isn't >"; } +}; +template +class LeMatcher : public ComparisonBase, Rhs, AnyLe> { + public: + explicit LeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLe>(rhs) { } + static const char* Desc() { return "is <="; } + static const char* NegatedDesc() { return "isn't <="; } +}; +template +class GeMatcher : public ComparisonBase, Rhs, AnyGe> { + public: + explicit GeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGe>(rhs) { } + static const char* Desc() { return "is >="; } + static const char* NegatedDesc() { return "isn't >="; } +}; + +// Implements polymorphic matchers MatchesRegex(regex) and +// ContainsRegex(regex), which can be used as a Matcher as long as +// T can be converted to a string. +class MatchesRegexMatcher { + public: + MatchesRegexMatcher(const RE* regex, bool full_match) + : regex_(regex), full_match_(full_match) {} + +#if GTEST_HAS_ABSL + bool MatchAndExplain(const absl::string_view& s, + MatchResultListener* listener) const { + return MatchAndExplain(std::string(s), listener); + } +#endif // GTEST_HAS_ABSL + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != nullptr && MatchAndExplain(std::string(s), listener); + } + + // Matches anything that can convert to std::string. + // + // This is a template, not just a plain function with const std::string&, + // because absl::string_view has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const std::string& s2(s); + return full_match_ ? RE::FullMatch(s2, *regex_) + : RE::PartialMatch(s2, *regex_); + } + + void DescribeTo(::std::ostream* os) const { + *os << (full_match_ ? "matches" : "contains") << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't " << (full_match_ ? "match" : "contain") + << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + private: + const std::shared_ptr regex_; + const bool full_match_; +}; +} // namespace internal + +// Matches a string that fully matches regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher MatchesRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); +} +inline PolymorphicMatcher MatchesRegex( + const std::string& regex) { + return MatchesRegex(new internal::RE(regex)); +} + +// Matches a string that contains regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher ContainsRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); +} +inline PolymorphicMatcher ContainsRegex( + const std::string& regex) { + return ContainsRegex(new internal::RE(regex)); +} + +// Creates a polymorphic matcher that matches anything equal to x. +// Note: if the parameter of Eq() were declared as const T&, Eq("foo") +// wouldn't compile. +template +inline internal::EqMatcher Eq(T x) { return internal::EqMatcher(x); } + +// Constructs a Matcher from a 'value' of type T. The constructed +// matcher matches any value that's equal to 'value'. +template +Matcher::Matcher(T value) { *this = Eq(value); } + +// Creates a monomorphic matcher that matches anything with type Lhs +// and equal to rhs. A user may need to use this instead of Eq(...) +// in order to resolve an overloading ambiguity. +// +// TypedEq(x) is just a convenient short-hand for Matcher(Eq(x)) +// or Matcher(x), but more readable than the latter. +// +// We could define similar monomorphic matchers for other comparison +// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do +// it yet as those are used much less than Eq() in practice. A user +// can always write Matcher(Lt(5)) to be explicit about the type, +// for example. +template +inline Matcher TypedEq(const Rhs& rhs) { return Eq(rhs); } + +// Creates a polymorphic matcher that matches anything >= x. +template +inline internal::GeMatcher Ge(Rhs x) { + return internal::GeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything > x. +template +inline internal::GtMatcher Gt(Rhs x) { + return internal::GtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything <= x. +template +inline internal::LeMatcher Le(Rhs x) { + return internal::LeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything < x. +template +inline internal::LtMatcher Lt(Rhs x) { + return internal::LtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything != x. +template +inline internal::NeMatcher Ne(Rhs x) { + return internal::NeMatcher(x); +} +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046 + +#endif // GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ diff --git a/test/gtest/include/gtest/gtest-message.h b/test/gtest/include/gtest/gtest-message.h index fe879bca79..4a80e11e6b 100644 --- a/test/gtest/include/gtest/gtest-message.h +++ b/test/gtest/include/gtest/gtest-message.h @@ -26,10 +26,9 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the Message class. // @@ -43,13 +42,19 @@ // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include +#include #include "gtest/internal/gtest-port.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. void operator<<(const testing::internal::Secret&, int); @@ -102,14 +107,6 @@ class GTEST_API_ Message { *ss_ << str; } -#if GTEST_OS_SYMBIAN - // Streams a value (either a pointer or not) to this object. - template - inline Message& operator <<(const T& value) { - StreamHelper(typename internal::is_pointer::type(), value); - return *this; - } -#else // Streams a non-pointer value to this object. template inline Message& operator <<(const T& val) { @@ -147,14 +144,13 @@ class GTEST_API_ Message { // as "(null)". template inline Message& operator <<(T* const& pointer) { // NOLINT - if (pointer == NULL) { + if (pointer == nullptr) { *ss_ << "(null)"; } else { *ss_ << pointer; } return *this; } -#endif // GTEST_OS_SYMBIAN // Since the basic IO manipulators are overloaded for both narrow // and wide streams, we have to provide this specialized definition @@ -183,12 +179,6 @@ class GTEST_API_ Message { Message& operator <<(const ::std::wstring& wstr); #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_GLOBAL_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::wstring& wstr); -#endif // GTEST_HAS_GLOBAL_WSTRING - // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". // @@ -196,32 +186,8 @@ class GTEST_API_ Message { std::string GetString() const; private: - -#if GTEST_OS_SYMBIAN - // These are needed as the Nokia Symbian Compiler cannot decide between - // const T& and const T* in a function template. The Nokia compiler _can_ - // decide between class template specializations for T and T*, so a - // tr1::type_traits-like is_pointer works, and we can overload on that. - template - inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - *ss_ << pointer; - } - } - template - inline void StreamHelper(internal::false_type /*is_pointer*/, - const T& value) { - // See the comments in Message& operator <<(const T&) above for why - // we need this using statement. - using ::operator <<; - *ss_ << value; - } -#endif // GTEST_OS_SYMBIAN - // We'll hold the text streamed to this object here. - const internal::scoped_ptr< ::std::stringstream> ss_; + const std::unique_ptr< ::std::stringstream> ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. @@ -247,4 +213,6 @@ std::string StreamableToString(const T& streamable) { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ diff --git a/test/gtest/include/gtest/gtest-param-test.h b/test/gtest/include/gtest/gtest-param-test.h index d6702c8f16..c2e6eae3d8 100644 --- a/test/gtest/include/gtest/gtest-param-test.h +++ b/test/gtest/include/gtest/gtest-param-test.h @@ -1,7 +1,3 @@ -// This file was GENERATED by command: -// pump.py gtest-param-test.h.pump -// DO NOT EDIT BY HAND!!! - // Copyright 2008, Google Inc. // All rights reserved. // @@ -31,13 +27,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: vladl@google.com (Vlad Losev) -// // Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) +// in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ @@ -76,10 +71,10 @@ TEST_P(FooTest, HasBlahBlah) { ... } -// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// Finally, you can use INSTANTIATE_TEST_SUITE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which +// (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // @@ -97,17 +92,17 @@ TEST_P(FooTest, HasBlahBlah) { // For more details, see comments at the definitions of these functions below // in this file. // -// The following statement will instantiate tests from the FooTest test case +// The following statement will instantiate tests from the FooTest test suite // each with parameter values "meeny", "miny", and "moe". -INSTANTIATE_TEST_CASE_P(InstantiationName, - FooTest, - Values("meeny", "miny", "moe")); +INSTANTIATE_TEST_SUITE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you -// can instantiate it more then once) the first argument to the -// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the -// actual test case name. Remember to pick unique prefixes for different +// can instantiate it more than once) the first argument to the +// INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the +// actual test suite name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // @@ -124,7 +119,7 @@ INSTANTIATE_TEST_CASE_P(InstantiationName, // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; -INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); +INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // @@ -133,9 +128,9 @@ INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // -// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests -// in the given test case, whether their definitions come before or -// AFTER the INSTANTIATE_TEST_CASE_P statement. +// Please note that INSTANTIATE_TEST_SUITE_P will instantiate all tests +// in the given test suite, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_SUITE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. @@ -179,31 +174,23 @@ TEST_P(DerivedTest, DoesBlah) { #endif // 0 -#include "gtest/internal/gtest-port.h" - -#if !GTEST_OS_SYMBIAN -# include -#endif +#include +#include -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" -#include "gtest/internal/gtest-param-util-generated.h" - -#if GTEST_HAS_PARAM_TEST +#include "gtest/internal/gtest-port.h" namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- -// parameterized tests. When a parameterized test case is instantiated +// parameterized tests. When a parameterized test suite is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // -// In the following sample, tests from test case FooTest are instantiated +// In the following sample, tests from test suite FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; @@ -212,7 +199,7 @@ namespace testing { // } // TEST_P(FooTest, TestThat) { // } -// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// INSTANTIATE_TEST_SUITE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. @@ -269,13 +256,13 @@ internal::ParamGenerator Range(T start, T end) { // // Examples: // -// This instantiates tests from test case StringTest +// This instantiates tests from test suite StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings)); // -// This instantiates tests from test case StlStringTest +// This instantiates tests from test suite StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { @@ -285,9 +272,9 @@ internal::ParamGenerator Range(T start, T end) { // return v; // } // -// INSTANTIATE_TEST_CASE_P(CharSequence, -// StlStringTest, -// ValuesIn(GetParameterStrings())); +// INSTANTIATE_TEST_SUITE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest @@ -300,16 +287,15 @@ internal::ParamGenerator Range(T start, T end) { // return list; // } // ::std::list l = GetParameterChars(); -// INSTANTIATE_TEST_CASE_P(CharSequence2, -// CharTest, -// ValuesIn(l.begin(), l.end())); +// INSTANTIATE_TEST_SUITE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> + typename std::iterator_traits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { - typedef typename ::testing::internal::IteratorTraits - ::value_type ParamType; + typedef typename std::iterator_traits::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } @@ -332,869 +318,22 @@ internal::ParamGenerator ValuesIn( // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // -// For example, this instantiates tests from test case BarTest each +// For example, this instantiates tests from test suite BarTest each // with values "one", "two", and "three": // -// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// INSTANTIATE_TEST_SUITE_P(NumSequence, +// BarTest, +// Values("one", "two", "three")); // -// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// This instantiates tests from test suite BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // -// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // -// Currently, Values() supports from 1 to 50 parameters. // -template -internal::ValueArray1 Values(T1 v1) { - return internal::ValueArray1(v1); -} - -template -internal::ValueArray2 Values(T1 v1, T2 v2) { - return internal::ValueArray2(v1, v2); -} - -template -internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { - return internal::ValueArray3(v1, v2, v3); -} - -template -internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { - return internal::ValueArray4(v1, v2, v3, v4); -} - -template -internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5) { - return internal::ValueArray5(v1, v2, v3, v4, v5); -} - -template -internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6) { - return internal::ValueArray6(v1, v2, v3, v4, v5, v6); -} - -template -internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7) { - return internal::ValueArray7(v1, v2, v3, v4, v5, - v6, v7); -} - -template -internal::ValueArray8 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { - return internal::ValueArray8(v1, v2, v3, v4, - v5, v6, v7, v8); -} - -template -internal::ValueArray9 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { - return internal::ValueArray9(v1, v2, v3, - v4, v5, v6, v7, v8, v9); -} - -template -internal::ValueArray10 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { - return internal::ValueArray10(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10); -} - -template -internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) { - return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); -} - -template -internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) { - return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); -} - -template -internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) { - return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); -} - -template -internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { - return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14); -} - -template -internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { - return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15); -} - -template -internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16) { - return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16); -} - -template -internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17) { - return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17); -} - -template -internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18) { - return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18); -} - -template -internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { - return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); -} - -template -internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { - return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); -} - -template -internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { - return internal::ValueArray21(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); -} - -template -internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22) { - return internal::ValueArray22(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22); -} - -template -internal::ValueArray23 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23) { - return internal::ValueArray23(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23); -} - -template -internal::ValueArray24 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24) { - return internal::ValueArray24(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24); -} - -template -internal::ValueArray25 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { - return internal::ValueArray25(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25); -} - -template -internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) { - return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); -} - -template -internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) { - return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); -} - -template -internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) { - return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28); -} - -template -internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) { - return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29); -} - -template -internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { - return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30); -} - -template -internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { - return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31); -} - -template -internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32) { - return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32); -} - -template -internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33) { - return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); -} - -template -internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34) { - return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); -} - -template -internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { - return internal::ValueArray35(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); -} - -template -internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { - return internal::ValueArray36(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36); -} - -template -internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37) { - return internal::ValueArray37(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37); -} - -template -internal::ValueArray38 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38) { - return internal::ValueArray38(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, - v33, v34, v35, v36, v37, v38); -} - -template -internal::ValueArray39 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38, T39 v39) { - return internal::ValueArray39(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, - v32, v33, v34, v35, v36, v37, v38, v39); -} - -template -internal::ValueArray40 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, - T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, - T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { - return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, - v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); -} - -template -internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { - return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, - v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); -} - -template -internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) { - return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, - v42); -} - -template -internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) { - return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, - v41, v42, v43); -} - -template -internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) { - return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, - v40, v41, v42, v43, v44); -} - -template -internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { - return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, - v39, v40, v41, v42, v43, v44, v45); -} - -template -internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { - return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46); -} - -template -internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { - return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); -} - -template -internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, - T48 v48) { - return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, - v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); -} - -template -internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, - T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, - T47 v47, T48 v48, T49 v49) { - return internal::ValueArray49(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, - v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); -} - -template -internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, - T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, - T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { - return internal::ValueArray50(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, - v48, v49, v50); +template +internal::ValueArray Values(T... v) { + return internal::ValueArray(std::move(v)...); } // Bool() allows generating tests with parameters in a set of (false, true). @@ -1207,7 +346,7 @@ internal::ValueArray50 { @@ -1215,13 +354,12 @@ internal::ValueArray50 Bool() { return Values(false, true); } -# if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // @@ -1230,192 +368,136 @@ inline internal::ParamGenerator Bool() { // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of -// tuple where T1, T2, ..., TN are the types +// std::tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // -// Combine can have up to 10 arguments. This number is currently limited -// by the maximum number of elements in the tuple implementation used by Google -// Test. +// Combine can have up to 10 arguments. // // Example: // -// This will instantiate tests in test case AnimalTest each one with +// This will instantiate tests in test suite AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest -// : public testing::TestWithParam > {...}; +// : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // -// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, -// Combine(Values("cat", "dog"), -// Values(BLACK, WHITE))); +// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest -// : public testing::TestWithParam > { +// : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. -// tie(external_flag_1, external_flag_2) = GetParam(); +// std::tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } -// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, -// Combine(Bool(), Bool())); -// -template -internal::CartesianProductHolder2 Combine( - const Generator1& g1, const Generator2& g2) { - return internal::CartesianProductHolder2( - g1, g2); -} - -template -internal::CartesianProductHolder3 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3) { - return internal::CartesianProductHolder3( - g1, g2, g3); -} - -template -internal::CartesianProductHolder4 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4) { - return internal::CartesianProductHolder4( - g1, g2, g3, g4); -} - -template -internal::CartesianProductHolder5 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5) { - return internal::CartesianProductHolder5( - g1, g2, g3, g4, g5); -} - -template -internal::CartesianProductHolder6 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6) { - return internal::CartesianProductHolder6( - g1, g2, g3, g4, g5, g6); -} - -template -internal::CartesianProductHolder7 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7) { - return internal::CartesianProductHolder7( - g1, g2, g3, g4, g5, g6, g7); -} - -template -internal::CartesianProductHolder8 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8) { - return internal::CartesianProductHolder8( - g1, g2, g3, g4, g5, g6, g7, g8); -} - -template -internal::CartesianProductHolder9 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9) { - return internal::CartesianProductHolder9( - g1, g2, g3, g4, g5, g6, g7, g8, g9); -} - -template -internal::CartesianProductHolder10 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9, - const Generator10& g10) { - return internal::CartesianProductHolder10( - g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); -} -# endif // GTEST_HAS_COMBINE - - - -# define TEST_P(test_case_name, test_name) \ - class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - : public test_case_name { \ - public: \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ - virtual void TestBody(); \ - private: \ - static int AddToRegistry() { \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ - #test_case_name, \ - #test_name, \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ - return 0; \ - } \ - static int gtest_registering_dummy_; \ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ - }; \ - int GTEST_TEST_CLASS_NAME_(test_case_name, \ - test_name)::gtest_registering_dummy_ = \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ - void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ - ::testing::internal::ParamGenerator \ - gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - int gtest_##prefix##test_case_name##_dummy_ = \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ +// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder Combine(const Generator&... g) { + return internal::CartesianProductHolder(g...); +} + +#define TEST_P(test_suite_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public test_suite_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + virtual void TestBody(); \ + \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + #test_suite_name, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestPattern( \ + GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory()); \ + return 0; \ + } \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() + +// The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify +// generator and an optional function or functor that generates custom test name +// suffixes based on the test parameters. Such a function or functor should +// accept one argument of type testing::TestParamInfo, and +// return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. + +#define GTEST_EXPAND_(arg) arg +#define GTEST_GET_FIRST_(first, ...) first +#define GTEST_GET_SECOND_(first, second, ...) second + +#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \ + static ::testing::internal::ParamGenerator \ + gtest_##prefix##test_suite_name##_EvalGenerator_() { \ + return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \ + } \ + static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo& info) { \ + if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))); \ + auto t = std::make_tuple(__VA_ARGS__); \ + static_assert(std::tuple_size::value <= 2, \ + "Too Many Args!"); \ + } \ + return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))))(info); \ + } \ + static int gtest_##prefix##test_suite_name##_dummy_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + #test_suite_name, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestSuiteInstantiation( \ + #prefix, >est_##prefix##test_suite_name##_EvalGenerator_, \ + >est_##prefix##test_suite_name##_EvalGenerateName_, \ __FILE__, __LINE__) -} // namespace testing +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TEST_CASE_P \ + static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \ + ""); \ + INSTANTIATE_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ -#endif // GTEST_HAS_PARAM_TEST +} // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/test/gtest/include/gtest/gtest-param-test.h.pump b/test/gtest/include/gtest/gtest-param-test.h.pump index 2dc9303b5e..7b7243f348 100644 --- a/test/gtest/include/gtest/gtest-param-test.h.pump +++ b/test/gtest/include/gtest/gtest-param-test.h.pump @@ -33,7 +33,7 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) +// in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // @@ -78,7 +78,7 @@ TEST_P(FooTest, HasBlahBlah) { // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which +// (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // @@ -184,15 +184,10 @@ TEST_P(DerivedTest, DoesBlah) { # include #endif -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-param-util-generated.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Functions producing parameter generators. @@ -272,7 +267,7 @@ internal::ParamGenerator Range(T start, T end) { // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": @@ -441,8 +436,6 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( ]] # endif // GTEST_HAS_COMBINE - - # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ @@ -453,14 +446,17 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ - #test_case_name, \ - #test_name, \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + #test_case_name, \ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__))->AddTestPattern(\ + GTEST_STRINGIFY_(test_case_name), \ + GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(\ + test_case_name, test_name)>()); \ return 0; \ } \ - static int gtest_registering_dummy_; \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ @@ -469,19 +465,37 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ - ::testing::internal::ParamGenerator \ +// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user +// to specify a function or functor that generates custom test name suffixes +// based on the test parameters. The function should accept one argument of +// type testing::TestParamInfo, and return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ + static ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - int gtest_##prefix##test_case_name##_dummy_ = \ + static ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo& info) { \ + return ::testing::internal::GetParamNameGen \ + (__VA_ARGS__)(info); \ + } \ + static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - __FILE__, __LINE__) + #test_case_name, \ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__))->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + >est_##prefix##test_case_name##_EvalGenerateName_, \ + __FILE__, __LINE__) } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/test/gtest/include/gtest/gtest-printers.h b/test/gtest/include/gtest/gtest-printers.h index b00f91e8c7..56a05450ef 100644 --- a/test/gtest/include/gtest/gtest-printers.h +++ b/test/gtest/include/gtest/gtest-printers.h @@ -26,10 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -46,6 +45,10 @@ // 2. operator<<(ostream&, const T&) defined in either foo or the // global namespace. // +// However if T is an STL-style container then it is printed element-wise +// unless foo::PrintTo(const T&, ostream*) is defined. Note that +// operator<<() is ignored for container types. +// // If none of the above is defined, it will print the debug string of // the value if it is a protocol buffer, or print the raw bytes in the // value otherwise. @@ -92,17 +95,27 @@ // being defined as many user-defined container types don't have // value_type. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ -#pragma GCC system_header +#include #include // NOLINT #include #include +#include +#include #include #include -#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_ABSL +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" +#endif // GTEST_HAS_ABSL namespace testing { @@ -122,7 +135,11 @@ enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) - kOtherType // anything else +#if GTEST_HAS_ABSL + kConvertibleToStringView, // a type implicitly convertible to + // absl::string_view +#endif + kOtherType // anything else }; // TypeWithoutFormatter::PrintValue(value, os) is called @@ -134,8 +151,10 @@ class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(reinterpret_cast(&value), - sizeof(value), os); + PrintBytesInObjectTo( + static_cast( + reinterpret_cast(std::addressof(value))), + sizeof(value), os); } }; @@ -148,10 +167,10 @@ template class TypeWithoutFormatter { public: static void PrintValue(const T& value, ::std::ostream* os) { - const ::testing::internal::string short_str = value.ShortDebugString(); - const ::testing::internal::string pretty_str = - short_str.length() <= kProtobufOneLinerMaxLength ? - short_str : ("\n" + value.DebugString()); + std::string pretty_str = value.ShortDebugString(); + if (pretty_str.length() > kProtobufOneLinerMaxLength) { + pretty_str = "\n" + value.DebugString(); + } *os << ("<" + pretty_str + ">"); } }; @@ -172,6 +191,19 @@ class TypeWithoutFormatter { } }; +#if GTEST_HAS_ABSL +template +class TypeWithoutFormatter { + public: + // Since T has neither operator<< nor PrintTo() but can be implicitly + // converted to absl::string_view, we print it as a absl::string_view. + // + // Note: the implementation is further below, as it depends on + // internal::PrintTo symbol which is defined later in the file. + static void PrintValue(const T& value, ::std::ostream* os); +}; +#endif + // Prints the given value to the given ostream. If the value is a // protocol message, its debug string is printed; if it's an enum or // of a type implicitly convertible to BiggestInt, it's printed as an @@ -199,10 +231,19 @@ class TypeWithoutFormatter { template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { - TypeWithoutFormatter::value ? kProtobuf : - internal::ImplicitlyConvertible::value ? - kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + TypeWithoutFormatter::value + ? kProtobuf + : std::is_convertible< + const T&, internal::BiggestInt>::value + ? kConvertibleToInteger + : +#if GTEST_HAS_ABSL + std::is_convertible< + const T&, absl::string_view>::value + ? kConvertibleToStringView + : +#endif + kOtherType)>::PrintValue(x, &os); return os; } @@ -251,6 +292,93 @@ void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { namespace testing { namespace internal { +// FormatForComparison::Format(value) formats a +// value of type ToPrint that is an operand of a comparison assertion +// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in +// the comparison, and is used to help determine the best way to +// format the value. In particular, when the value is a C string +// (char pointer) and the other operand is an STL string object, we +// want to format the C string as a string, since we know it is +// compared by value with the string object. If the value is a char +// pointer but the other operand is not an STL string object, we don't +// know whether the pointer is supposed to point to a NUL-terminated +// string, and thus want to print it as a pointer to be safe. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// The default case. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint& value) { + return ::testing::PrintToString(value); + } +}; + +// Array. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint* value) { + return FormatForComparison::Format(value); + } +}; + +// By default, print C string as pointers to be safe, as we don't know +// whether they actually point to a NUL-terminated string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ + template \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(static_cast(value)); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ + +// If a C string is compared with an STL string object, we know it's meant +// to point to a NUL-terminated string, and thus can print it as a string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ + template <> \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(value); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); + +#if GTEST_HAS_STD_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); +#endif + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char* or void*, and print it as a C string when it is compared +// against an std::string object, for example. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +std::string FormatForComparisonFailureMessage( + const T1& value, const T2& /* other_operand */) { + return FormatForComparison::Format(value); +} + // UniversalPrinter::Print(value, ostream_ptr) prints the given // value to the given ostream. The caller must ensure that // 'ostream_ptr' is not NULL, or the behavior is undefined. @@ -264,11 +392,18 @@ class UniversalPrinter; template void UniversalPrint(const T& value, ::std::ostream* os); +enum DefaultPrinterType { + kPrintContainer, + kPrintPointer, + kPrintFunctionPointer, + kPrintOther, +}; +template struct WrapPrinterType {}; + // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template -void DefaultPrintTo(IsContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; @@ -301,40 +436,34 @@ void DefaultPrintTo(IsContainer /* dummy */, // implementation-defined. Therefore they will be printed as raw // bytes.) template -void DefaultPrintTo(IsNotContainer /* dummy */, - true_type /* is a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, T* p, ::std::ostream* os) { - if (p == NULL) { + if (p == nullptr) { *os << "NULL"; } else { - // C++ doesn't allow casting from a function pointer to any object - // pointer. - // - // IsTrue() silences warnings: "Condition is always true", - // "unreachable code". - if (IsTrue(ImplicitlyConvertible::value)) { - // T is not a function type. We just call << to print p, - // relying on ADL to pick up user-defined << for their pointer - // types, if any. - *os << p; - } else { - // T is a function type, so '*os << p' doesn't do what we want - // (it just prints p as bool). We want to print p as a const - // void*. However, we cannot cast it to const void* directly, - // even using reinterpret_cast, as earlier versions of gcc - // (e.g. 3.4.5) cannot compile the cast when p is a function - // pointer. Casting to UInt64 first solves the problem. - *os << reinterpret_cast( - reinterpret_cast(p)); - } + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } +} +template +void DefaultPrintTo(WrapPrinterType /* dummy */, + T* p, ::std::ostream* os) { + if (p == nullptr) { + *os << "NULL"; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. + *os << reinterpret_cast(p); } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template -void DefaultPrintTo(IsNotContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } @@ -352,11 +481,8 @@ void DefaultPrintTo(IsNotContainer /* dummy */, // wants). template void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first two - // arguments determine which version will be picked. If T is an - // STL-style container, the version for container will be called; if - // T is a pointer, the pointer version will be called; otherwise the - // generic version will be called. + // DefaultPrintTo() is overloaded. The type of its first argument + // determines which version will be picked. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: @@ -368,13 +494,23 @@ void PrintTo(const T& value, ::std::ostream* os) { // elements; therefore we check for container types here to ensure // that our format is used. // - // The second argument of DefaultPrintTo() is needed to bypass a bug - // in Symbian's C++ compiler that prevents it from picking the right - // overload between: - // - // PrintTo(const T& x, ...); - // PrintTo(T* x, ...); - DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); + // Note that MSVC and clang-cl do allow an implicit conversion from + // pointer-to-function to pointer-to-object, but clang-cl warns on it. + // So don't use ImplicitlyConvertible if it can be helped since it will + // cause this warning, and use a separate overload of DefaultPrintTo for + // function pointers so that the `*os << p` in the object pointer overload + // doesn't cause that warning either. + DefaultPrintTo( + WrapPrinterType < + (sizeof(IsContainerTest(0)) == sizeof(IsContainer)) && + !IsRecursiveContainer::value + ? kPrintContainer + : !std::is_pointer::value + ? kPrintOther + : std::is_function::type>::value + ? kPrintFunctionPointer + : kPrintPointer > (), + value, os); } // The following list of PrintTo() overloads tells @@ -453,27 +589,13 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { } } -// Overloads for ::string and ::std::string. -#if GTEST_HAS_GLOBAL_STRING -GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); -inline void PrintTo(const ::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_STRING - +// Overloads for ::std::string. GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } -// Overloads for ::wstring and ::std::wstring. -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - +// Overloads for ::std::wstring. #if GTEST_HAS_STD_WSTRING GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { @@ -481,86 +603,45 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_TR1_TUPLE -// Overload for ::std::tr1::tuple. Needed for printing function arguments, -// which are packed as tuples. - -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os); - -// Overloaded PrintTo() for tuples of various arities. We support -// tuples of up-to 10 fields. The following implementation works -// regardless of whether tr1::tuple is implemented using the -// non-standard variadic template feature or not. - -inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { - PrintTupleTo(t, os); +#if GTEST_HAS_ABSL +// Overload for absl::string_view. +inline void PrintTo(absl::string_view sp, ::std::ostream* os) { + PrintTo(::std::string(sp), os); } +#endif // GTEST_HAS_ABSL -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} +inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); +template +void PrintTo(std::reference_wrapper ref, ::std::ostream* os) { + UniversalPrinter::Print(ref.get(), os); } -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T&, std::integral_constant, + ::std::ostream*) {} + +template +void PrintTupleTo(const T& t, std::integral_constant, + ::std::ostream* os) { + PrintTupleTo(t, std::integral_constant(), os); + GTEST_INTENTIONAL_CONST_COND_PUSH_() + if (I > 1) { + GTEST_INTENTIONAL_CONST_COND_POP_() + *os << ", "; + } + UniversalPrinter::type>::Print( + std::get(t), os); } -template -void PrintTo( - const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); +template +void PrintTo(const ::std::tuple& t, ::std::ostream* os) { + *os << "("; + PrintTupleTo(t, std::integral_constant(), os); + *os << ")"; } -#endif // GTEST_HAS_TR1_TUPLE // Overload for std::pair. template @@ -581,10 +662,7 @@ class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) // Note: we deliberately don't call this PrintTo(), as that name // conflicts with ::testing::internal::PrintTo in the body of the @@ -601,11 +679,51 @@ class UniversalPrinter { PrintTo(value, os); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() }; +#if GTEST_HAS_ABSL + +// Printer for absl::optional + +template +class UniversalPrinter<::absl::optional> { + public: + static void Print(const ::absl::optional& value, ::std::ostream* os) { + *os << '('; + if (!value) { + *os << "nullopt"; + } else { + UniversalPrint(*value, os); + } + *os << ')'; + } +}; + +// Printer for absl::variant + +template +class UniversalPrinter<::absl::variant> { + public: + static void Print(const ::absl::variant& value, ::std::ostream* os) { + *os << '('; + absl::visit(Visitor{os}, value); + *os << ')'; + } + + private: + struct Visitor { + template + void operator()(const U& u) const { + *os << "'" << GetTypeName() << "' with value "; + UniversalPrint(u, os); + } + ::std::ostream* os; + }; +}; + +#endif // GTEST_HAS_ABSL + // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template @@ -619,7 +737,6 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. - // TODO(wan@google.com): let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { @@ -655,10 +772,7 @@ class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) static void Print(const T& value, ::std::ostream* os) { // Prints the address of the value. We use reinterpret_cast here @@ -669,9 +783,7 @@ class UniversalPrinter { UniversalPrint(value, os); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() }; // Prints a value tersely: for a reference type, the referenced value @@ -703,10 +815,10 @@ template <> class UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { - if (str == NULL) { + if (str == nullptr) { *os << "NULL"; } else { - UniversalPrint(string(str), os); + UniversalPrint(std::string(str), os); } } }; @@ -723,7 +835,7 @@ template <> class UniversalTersePrinter { public: static void Print(const wchar_t* str, ::std::ostream* os) { - if (str == NULL) { + if (str == nullptr) { *os << "NULL"; } else { UniversalPrint(::std::wstring(str), os); @@ -757,77 +869,22 @@ void UniversalPrint(const T& value, ::std::ostream* os) { UniversalPrinter::Print(value, os); } -#if GTEST_HAS_TR1_TUPLE -typedef ::std::vector Strings; - -// This helper template allows PrintTo() for tuples and -// UniversalTersePrintTupleFieldsToStrings() to be defined by -// induction on the number of tuple fields. The idea is that -// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N -// fields in tuple t, and can be defined in terms of -// TuplePrefixPrinter. - -// The inductive case. -template -struct TuplePrefixPrinter { - // Prints the first N fields of a tuple. - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - TuplePrefixPrinter::PrintPrefixTo(t, os); - *os << ", "; - UniversalPrinter::type> - ::Print(::std::tr1::get(t), os); - } +typedef ::std::vector< ::std::string> Strings; // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); - ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Base cases. -template <> -struct TuplePrefixPrinter<0> { - template - static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} - - template - static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} -}; -// We have to specialize the entire TuplePrefixPrinter<> class -// template here, even though the definition of -// TersePrintPrefixToStrings() is the same as the generic version, as -// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't -// support specializing a method template of a class template. -template <> -struct TuplePrefixPrinter<1> { - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - UniversalPrinter::type>:: - Print(::std::tr1::get<0>(t), os); - } - - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get<0>(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os) { - *os << "("; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - PrintPrefixTo(t, os); - *os << ")"; +template +void TersePrintPrefixToStrings(const Tuple&, std::integral_constant, + Strings*) {} +template +void TersePrintPrefixToStrings(const Tuple& t, + std::integral_constant, + Strings* strings) { + TersePrintPrefixToStrings(t, std::integral_constant(), + strings); + ::std::stringstream ss; + UniversalTersePrint(std::get(t), &ss); + strings->push_back(ss.str()); } // Prints the fields of a tuple tersely to a string vector, one @@ -836,14 +893,24 @@ void PrintTupleTo(const T& t, ::std::ostream* os) { template Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - TersePrintPrefixToStrings(value, &result); + TersePrintPrefixToStrings( + value, std::integral_constant::value>(), + &result); return result; } -#endif // GTEST_HAS_TR1_TUPLE } // namespace internal +#if GTEST_HAS_ABSL +namespace internal2 { +template +void TypeWithoutFormatter::PrintValue( + const T& value, ::std::ostream* os) { + internal::PrintTo(absl::string_view(value), os); +} +} // namespace internal2 +#endif + template ::std::string PrintToString(const T& value) { ::std::stringstream ss; @@ -853,4 +920,9 @@ ::std::string PrintToString(const T& value) { } // namespace testing +// Include any custom printer added by the local installation. +// We must include this header at the end to make sure it can use the +// declarations from this file. +#include "gtest/internal/custom/gtest-printers.h" + #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ diff --git a/test/gtest/include/gtest/gtest-spi.h b/test/gtest/include/gtest/gtest-spi.h index f63fa9a1b2..aa38870e8e 100644 --- a/test/gtest/include/gtest/gtest-spi.h +++ b/test/gtest/include/gtest/gtest-spi.h @@ -26,17 +26,21 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). +// GOOGLETEST_CM0004 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #include "gtest/gtest.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // This helper class can be used to mock out Google Test failure reporting @@ -68,14 +72,15 @@ class GTEST_API_ ScopedFakeTestPartResultReporter TestPartResultArray* result); // The d'tor restores the previous test part result reporter. - virtual ~ScopedFakeTestPartResultReporter(); + ~ScopedFakeTestPartResultReporter() override; // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult& result) override; + private: void Init(); @@ -97,13 +102,12 @@ class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr); + TestPartResult::Type type, const std::string& substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; - const string substr_; + const std::string substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; @@ -112,6 +116,8 @@ class GTEST_API_ SingleFailureChecker { } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' diff --git a/test/gtest/include/gtest/gtest-test-part.h b/test/gtest/include/gtest/gtest-test-part.h index 77eb844839..05a7985358 100644 --- a/test/gtest/include/gtest/gtest-test-part.h +++ b/test/gtest/include/gtest/gtest-test-part.h @@ -27,8 +27,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: mheule@google.com (Markus Heule) -// +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ @@ -38,6 +37,9 @@ #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // A copyable object representing the result of a test part (i.e. an @@ -51,22 +53,20 @@ class GTEST_API_ TestPartResult { enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. - kFatalFailure // Failed and the test should be terminated. + kFatalFailure, // Failed and the test should be terminated. + kSkip // Skipped. }; // C'tor. TestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestPartResult object. - TestPartResult(Type a_type, - const char* a_file_name, - int a_line_number, + TestPartResult(Type a_type, const char* a_file_name, int a_line_number, const char* a_message) : type_(a_type), - file_name_(a_file_name == NULL ? "" : a_file_name), + file_name_(a_file_name == nullptr ? "" : a_file_name), line_number_(a_line_number), summary_(ExtractSummary(a_message)), - message_(a_message) { - } + message_(a_message) {} // Gets the outcome of the test part. Type type() const { return type_; } @@ -74,7 +74,7 @@ class GTEST_API_ TestPartResult { // Gets the name of the source file where the test part took place, or // NULL if it's unknown. const char* file_name() const { - return file_name_.empty() ? NULL : file_name_.c_str(); + return file_name_.empty() ? nullptr : file_name_.c_str(); } // Gets the line in the source file where the test part took place, @@ -87,18 +87,21 @@ class GTEST_API_ TestPartResult { // Gets the message associated with the test part. const char* message() const { return message_.c_str(); } - // Returns true iff the test part passed. - bool passed() const { return type_ == kSuccess; } + // Returns true if and only if the test part was skipped. + bool skipped() const { return type_ == kSkip; } - // Returns true iff the test part failed. - bool failed() const { return type_ != kSuccess; } + // Returns true if and only if the test part passed. + bool passed() const { return type_ == kSuccess; } - // Returns true iff the test part non-fatally failed. + // Returns true if and only if the test part non-fatally failed. bool nonfatally_failed() const { return type_ == kNonFatalFailure; } - // Returns true iff the test part fatally failed. + // Returns true if and only if the test part fatally failed. bool fatally_failed() const { return type_ == kFatalFailure; } + // Returns true if and only if the test part failed. + bool failed() const { return fatally_failed() || nonfatally_failed(); } + private: Type type_; @@ -143,7 +146,7 @@ class GTEST_API_ TestPartResultArray { }; // This interface knows how to report a test part result. -class TestPartResultReporterInterface { +class GTEST_API_ TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} @@ -162,8 +165,8 @@ class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); - virtual ~HasNewFatalFailureHelper(); - virtual void ReportTestPartResult(const TestPartResult& result); + ~HasNewFatalFailureHelper() override; + void ReportTestPartResult(const TestPartResult& result) override; bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; @@ -176,4 +179,6 @@ class GTEST_API_ HasNewFatalFailureHelper } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ diff --git a/test/gtest/include/gtest/gtest-typed-test.h b/test/gtest/include/gtest/gtest-typed-test.h index d5dc8be1c2..095ce05802 100644 --- a/test/gtest/include/gtest/gtest-typed-test.h +++ b/test/gtest/include/gtest/gtest-typed-test.h @@ -26,12 +26,12 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + + +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ -#pragma GCC system_header // This header implements typed tests and type-parameterized tests. @@ -52,22 +52,22 @@ class FooTest : public testing::Test { T value_; }; -// Next, associate a list of types with the test case, which will be +// Next, associate a list of types with the test suite, which will be // repeated for each type in the list. The typedef is necessary for // the macro to parse correctly. typedef testing::Types MyTypes; -TYPED_TEST_CASE(FooTest, MyTypes); +TYPED_TEST_SUITE(FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: -// TYPED_TEST_CASE(FooTest, int); +// TYPED_TEST_SUITE(FooTest, int); // Then, use TYPED_TEST() instead of TEST_F() to define as many typed -// tests for this test case as you want. +// tests for this test suite as you want. TYPED_TEST(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - // Since we are inside a derived class template, C++ requires use to - // visit the members of FooTest via 'this'. + // Inside a test, refer to the special name TypeParam to get the type + // parameter. Since we are inside a derived class template, C++ requires + // us to visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the TestFixture:: @@ -83,6 +83,24 @@ TYPED_TEST(FooTest, DoesBlah) { TYPED_TEST(FooTest, HasPropertyA) { ... } +// TYPED_TEST_SUITE takes an optional third argument which allows to specify a +// class that generates custom test name suffixes based on the type. This should +// be a class which has a static template function GetName(int index) returning +// a string for each type. The provided integer index equals the index of the +// type in the provided type list. In many cases the index can be ignored. +// +// For example: +// class MyTypeNames { +// public: +// template +// static std::string GetName(int) { +// if (std::is_same()) return "char"; +// if (std::is_same()) return "int"; +// if (std::is_same()) return "unsignedInt"; +// } +// }; +// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames); + #endif // 0 // Type-parameterized tests are abstract test patterns parameterized @@ -108,13 +126,13 @@ class FooTest : public testing::Test { ... }; -// Next, declare that you will define a type-parameterized test case +// Next, declare that you will define a type-parameterized test suite // (the _P suffix is for "parameterized" or "pattern", whichever you // prefer): -TYPED_TEST_CASE_P(FooTest); +TYPED_TEST_SUITE_P(FooTest); // Then, use TYPED_TEST_P() to define as many type-parameterized tests -// for this type-parameterized test case as you want. +// for this type-parameterized test suite as you want. TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; @@ -125,10 +143,10 @@ TYPED_TEST_P(FooTest, HasPropertyA) { ... } // Now the tricky part: you need to register all test patterns before // you can instantiate them. The first argument of the macro is the -// test case name; the rest are the names of the tests in this test +// test suite name; the rest are the names of the tests in this test // case. -REGISTER_TYPED_TEST_CASE_P(FooTest, - DoesBlah, HasPropertyA); +REGISTER_TYPED_TEST_SUITE_P(FooTest, + DoesBlah, HasPropertyA); // Finally, you are free to instantiate the pattern with the types you // want. If you put the above code in a header file, you can #include @@ -136,14 +154,19 @@ REGISTER_TYPED_TEST_CASE_P(FooTest, // // To distinguish different instances of the pattern, the first // argument to the INSTANTIATE_* macro is a prefix that will be added -// to the actual test case name. Remember to pick unique prefixes for +// to the actual test suite name. Remember to pick unique prefixes for // different instances. typedef testing::Types MyTypes; -INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: -// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); +// +// Similar to the optional argument of TYPED_TEST_SUITE above, +// INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to +// generate custom names. +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames); #endif // 0 @@ -157,34 +180,53 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the -// given test case. -# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define TYPED_TEST_CASE(CaseName, Types) \ - typedef ::testing::internal::TypeList< Types >::type \ - GTEST_TYPE_PARAMS_(CaseName) - -# define TYPED_TEST(CaseName, TestName) \ - template \ - class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ - : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTest< \ - CaseName, \ - ::testing::internal::TemplateSel< \ - GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ - GTEST_TYPE_PARAMS_(CaseName)>::Register(\ - "", #CaseName, #TestName, 0); \ - template \ - void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() +// given test suite. +#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_ + +// Expands to the name of the typedef for the NameGenerator, responsible for +// creating the suffixes of the name. +#define GTEST_NAME_GENERATOR_(TestSuiteName) \ + gtest_type_params_##TestSuiteName##_NameGenerator + +#define TYPED_TEST_SUITE(CaseName, Types, ...) \ + typedef ::testing::internal::TypeList::type GTEST_TYPE_PARAMS_( \ + CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ + GTEST_NAME_GENERATOR_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##CaseName##_##TestName##_registered_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel, \ + GTEST_TYPE_PARAMS_( \ + CaseName)>::Register("", \ + ::testing::internal::CodeLocation( \ + __FILE__, __LINE__), \ + #CaseName, #TestName, 0, \ + ::testing::internal::GenerateNames< \ + GTEST_NAME_GENERATOR_(CaseName), \ + GTEST_TYPE_PARAMS_(CaseName)>()); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, \ + TestName)::TestBody() + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE \ + static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \ + TYPED_TEST_SUITE +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_HAS_TYPED_TEST @@ -195,65 +237,93 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for -// the given type-parameterized test case are defined in. The exact +// the given type-parameterized test suite are defined in. The exact // name of the namespace is subject to change without notice. -# define GTEST_CASE_NAMESPACE_(TestCaseName) \ - gtest_case_##TestCaseName##_ +#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the variable used to remember the names of -// the defined tests in the given test case. -# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ - gtest_typed_test_case_p_state_##TestCaseName##_ +// the defined tests in the given test suite. +#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \ + gtest_typed_test_suite_p_state_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. // // Expands to the name of the variable used to remember the names of -// the registered tests in the given test case. -# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ - gtest_registered_test_names_##TestCaseName##_ +// the registered tests in the given test suite. +#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \ + gtest_registered_test_names_##TestSuiteName##_ // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. -# define TYPED_TEST_CASE_P(CaseName) \ - static ::testing::internal::TypedTestCasePState \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) - -# define TYPED_TEST_P(CaseName, TestName) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - template \ - class TestName : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ - __FILE__, __LINE__, #CaseName, #TestName); \ - } \ - template \ - void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() - -# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ - } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ +#define TYPED_TEST_SUITE_P(SuiteName) \ + static ::testing::internal::TypedTestSuitePState \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE_P \ + static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \ + TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define TYPED_TEST_P(SuiteName, TestName) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + template \ + class TestName : public SuiteName { \ + private: \ + typedef SuiteName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ + __FILE__, __LINE__, #SuiteName, #TestName); \ + } \ + template \ + void GTEST_SUITE_NAMESPACE_( \ + SuiteName)::TestName::TestBody() + +#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_( \ + SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ __FILE__, __LINE__, #__VA_ARGS__) -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ - bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTestCase::type>::Register(\ - #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define REGISTER_TYPED_TEST_CASE_P \ + static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \ + ""); \ + REGISTER_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ + static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestSuite< \ + SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ + ::testing::internal::TypeList::type>:: \ + Register(#Prefix, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), #SuiteName, \ + GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ + ::testing::internal::GenerateNames< \ + ::testing::internal::NameGeneratorSelector< \ + __VA_ARGS__>::type, \ + ::testing::internal::TypeList::type>()) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TYPED_TEST_CASE_P \ + static_assert( \ + ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \ + INSTANTIATE_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_HAS_TYPED_TEST_P diff --git a/test/gtest/include/gtest/gtest.h b/test/gtest/include/gtest/gtest.h index 6fa0a3925e..dbe5b1c2c3 100644 --- a/test/gtest/include/gtest/gtest.h +++ b/test/gtest/include/gtest/gtest.h @@ -26,10 +26,9 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. @@ -48,16 +47,22 @@ // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ +#include #include +#include #include +#include #include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" #include "gtest/gtest-death-test.h" +#include "gtest/gtest-matchers.h" #include "gtest/gtest-message.h" #include "gtest/gtest-param-test.h" #include "gtest/gtest-printers.h" @@ -65,23 +70,20 @@ #include "gtest/gtest-test-part.h" #include "gtest/gtest-typed-test.h" -// Depending on the platform, different string classes are available. -// On Linux, in addition to ::std::string, Google also makes use of -// class ::string, which has the same interface as ::std::string, but -// has a different implementation. -// -// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that -// ::string is available AND is a distinct type to ::std::string, or -// define it to 0 to indicate otherwise. -// -// If the user's ::std::string and ::string are the same class due to -// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. -// -// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined -// heuristically. +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) namespace testing { +// Silence C4100 (unreferenced formal parameter) and 4805 +// unsafe mix of type 'const int' and type 'const bool' +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4805) +# pragma warning(disable:4100) +#endif + + // Declares the flags. // This flag temporary enables the disabled tests. @@ -103,6 +105,10 @@ GTEST_DECLARE_string_(color); // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); +// This flag controls whether Google Test installs a signal handler that dumps +// debugging information when fatal signals are raised. +GTEST_DECLARE_bool_(install_failure_signal_handler); + // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); @@ -115,6 +121,9 @@ GTEST_DECLARE_string_(output); // test. GTEST_DECLARE_bool_(print_time); +// This flags control whether Google Test prints UTF8 characters as text. +GTEST_DECLARE_bool_(print_utf8); + // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); @@ -135,7 +144,7 @@ GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a -// non-zero code otherwise. +// non-zero code otherwise. For use with an external test framework. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported @@ -143,6 +152,10 @@ GTEST_DECLARE_bool_(throw_on_failure); // the specified host machine. GTEST_DECLARE_string_(stream_result_to); +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DECLARE_string_(flagfile); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; @@ -160,6 +173,7 @@ class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; +class FuchsiaDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); @@ -170,7 +184,12 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; -class TestCase; +class TestSuite; + +// Old API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TestCase = TestSuite; +#endif class TestInfo; class UnitTest; @@ -258,10 +277,38 @@ class GTEST_API_ AssertionResult { // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); + +#if defined(_MSC_VER) && _MSC_VER < 1910 + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) +#endif + // Used in the EXPECT_TRUE/FALSE(bool_expression). - explicit AssertionResult(bool success) : success_(success) {} + // + // T must be contextually convertible to bool. + // + // The second parameter prevents this overload from being considered if + // the argument is implicitly convertible to AssertionResult. In that case + // we want AssertionResult's copy constructor to be used. + template + explicit AssertionResult( + const T& success, + typename std::enable_if< + !std::is_convertible::value>::type* + /*enabler*/ + = nullptr) + : success_(success) {} + +#if defined(_MSC_VER) && _MSC_VER < 1910 + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + + // Assignment operator. + AssertionResult& operator=(AssertionResult other) { + swap(other); + return *this; + } - // Returns true iff the assertion succeeded. + // Returns true if and only if the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. @@ -272,9 +319,8 @@ class GTEST_API_ AssertionResult { // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { - return message_.get() != NULL ? message_->c_str() : ""; + return message_.get() != nullptr ? message_->c_str() : ""; } - // TODO(vladl@google.com): Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } @@ -295,20 +341,20 @@ class GTEST_API_ AssertionResult { private: // Appends the contents of message to message_. void AppendMessage(const Message& a_message) { - if (message_.get() == NULL) - message_.reset(new ::std::string); + if (message_.get() == nullptr) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } + // Swap the contents of this AssertionResult with other. + void swap(AssertionResult& other); + // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. - internal::scoped_ptr< ::std::string> message_; - - GTEST_DISALLOW_ASSIGN_(AssertionResult); + std::unique_ptr< ::std::string> message_; }; // Makes a successful assertion result. @@ -321,22 +367,31 @@ GTEST_API_ AssertionResult AssertionFailure(); // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); +} // namespace testing + +// Includes the auto-generated header that implements a family of generic +// predicate assertion macros. This include comes late because it relies on +// APIs declared above. +#include "gtest/gtest_pred_impl.h" + +namespace testing { + // The abstract class that all tests inherit from. // -// In Google Test, a unit test program contains one or many TestCases, and -// each TestCase contains one or many Tests. +// In Google Test, a unit test program contains one or many TestSuites, and +// each TestSuite contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does // this for you. // // The only time you derive from Test is when defining a test fixture -// to be used a TEST_F. For example: +// to be used in a TEST_F. For example: // // class FooTest : public testing::Test { // protected: -// virtual void SetUp() { ... } -// virtual void TearDown() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } // ... // }; // @@ -348,49 +403,57 @@ class GTEST_API_ Test { public: friend class TestInfo; - // Defines types for pointers to functions that set up and tear down - // a test case. - typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; - typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; - // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // - // Google Test will call Foo::SetUpTestCase() before running the first + // Google Test will call Foo::SetUpTestSuite() before running the first // test in test case Foo. Hence a sub-class can define its own - // SetUpTestCase() method to shadow the one defined in the super + // SetUpTestSuite() method to shadow the one defined in the super // class. - static void SetUpTestCase() {} + // Failures that happen during SetUpTestSuite are logged but otherwise + // ignored. + static void SetUpTestSuite() {} - // Tears down the stuff shared by all tests in this test case. + // Tears down the stuff shared by all tests in this test suite. // - // Google Test will call Foo::TearDownTestCase() after running the last + // Google Test will call Foo::TearDownTestSuite() after running the last // test in test case Foo. Hence a sub-class can define its own - // TearDownTestCase() method to shadow the one defined in the super + // TearDownTestSuite() method to shadow the one defined in the super // class. + // Failures that happen during TearDownTestSuite are logged but otherwise + // ignored. + static void TearDownTestSuite() {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ static void TearDownTestCase() {} + static void SetUpTestCase() {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ - // Returns true iff the current test has a fatal failure. + // Returns true if and only if the current test has a fatal failure. static bool HasFatalFailure(); - // Returns true iff the current test has a non-fatal failure. + // Returns true if and only if the current test has a non-fatal failure. static bool HasNonfatalFailure(); - // Returns true iff the current test has a (either fatal or + // Returns true if and only if the current test was skipped. + static bool IsSkipped(); + + // Returns true if and only if the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } - // Logs a property for the current test, test case, or for the entire + // Logs a property for the current test, test suite, or for the entire // invocation of the test program when used outside of the context of a - // test case. Only the last value for a given key is remembered. These + // test suite. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the element. Properties recorded from fixture's - // SetUpTestCase or TearDownTestCase are logged as attributes of the + // SetUpTestSuite or TearDownTestSuite are logged as attributes of the // corresponding element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google @@ -409,8 +472,8 @@ class GTEST_API_ Test { virtual void TearDown(); private: - // Returns true iff the current test has the same fixture class as - // the first test in the current test case. + // Returns true if and only if the current test has the same fixture class + // as the first test in the current test suite. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. @@ -428,27 +491,26 @@ class GTEST_API_ Test { // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } - // Uses a GTestFlagSaver to save and restore all Google Test flags. - const internal::GTestFlagSaver* const gtest_flag_saver_; + const std::unique_ptr gtest_flag_saver_; - // Often a user mis-spells SetUp() as Setup() and spends a long time + // Often a user misspells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it - // will be a conflict if a user declares void Setup() in his test - // fixture. + // will be a conflict if void Setup() is declared in the user's + // test fixture. // // - This method is private, so it will be another compiler error - // if a user calls it from his test fixture. + // if the method is called from the user's test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); @@ -512,24 +574,30 @@ class GTEST_API_ TestResult { // Returns the number of the test properties. int test_property_count() const; - // Returns true iff the test passed (i.e. no test part failed). - bool Passed() const { return !Failed(); } + // Returns true if and only if the test passed (i.e. no test part failed). + bool Passed() const { return !Skipped() && !Failed(); } - // Returns true iff the test failed. + // Returns true if and only if the test was skipped. + bool Skipped() const; + + // Returns true if and only if the test failed. bool Failed() const; - // Returns true iff the test fatally failed. + // Returns true if and only if the test fatally failed. bool HasFatalFailure() const; - // Returns true iff the test has a non-fatal failure. + // Returns true if and only if the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } - // Returns the i-th test part result among all the results. i can range - // from 0 to test_property_count() - 1. If i is not in that range, aborts - // the program. + // Gets the time of the test case start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + + // Returns the i-th test part result among all the results. i can range from 0 + // to total_part_count() - 1. If i is not in that range, aborts the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to @@ -539,13 +607,14 @@ class GTEST_API_ TestResult { private: friend class TestInfo; - friend class TestCase; + friend class TestSuite; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; + friend class internal::FuchsiaDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { @@ -557,6 +626,9 @@ class GTEST_API_ TestResult { return test_properties_; } + // Sets the start time. + void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; } + // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } @@ -570,8 +642,8 @@ class GTEST_API_ TestResult { const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test - // testcase tags. Returns true if the property is valid. - // TODO(russr): Validate attribute names are legal and human readable. + // testsuite tags. Returns true if the property is valid. + // FIXME: Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); @@ -600,6 +672,8 @@ class GTEST_API_ TestResult { std::vector test_properties_; // Running count of death tests. int death_test_count_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; @@ -609,7 +683,7 @@ class GTEST_API_ TestResult { // A TestInfo object stores the following information about a test: // -// Test case name +// Test suite name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked @@ -624,8 +698,13 @@ class GTEST_API_ TestInfo { // don't inherit from TestInfo. ~TestInfo(); - // Returns the test case name. - const char* test_case_name() const { return test_case_name_.c_str(); } + // Returns the test suite name. + const char* test_suite_name() const { return test_suite_name_.c_str(); } + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const char* test_case_name() const { return test_suite_name(); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the test name. const char* name() const { return name_.c_str(); } @@ -633,25 +712,32 @@ class GTEST_API_ TestInfo { // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. const char* value_param() const { - if (value_param_.get() != NULL) - return value_param_->c_str(); - return NULL; + if (value_param_.get() != nullptr) return value_param_->c_str(); + return nullptr; } + // Returns the file name where this test is defined. + const char* file() const { return location_.file.c_str(); } + + // Returns the line where this test is defined. + int line() const { return location_.line; } + + // Return true if this test should not be run because it's in another shard. + bool is_in_another_shard() const { return is_in_another_shard_; } + // Returns true if this test should run, that is if the test is not // disabled (or it is disabled but the also_run_disabled_tests flag has // been specified) and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. - // The full name of a test Bar in test case Foo is defined as + // The full name of a test Bar in test suite Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, @@ -664,12 +750,11 @@ class GTEST_API_ TestInfo { // contains the character 'A' or starts with "Foo.". bool should_run() const { return should_run_; } - // Returns true iff this test will appear in the XML report. + // Returns true if and only if this test will appear in the XML report. bool is_reportable() const { - // For now, the XML report includes all tests matching the filter. - // In the future, we may trim tests that are excluded because of - // sharding. - return matches_filter_; + // The XML report includes tests matching the filter, excluding those + // run in other shards. + return matches_filter_ && !is_in_another_shard_; } // Returns the result of the test. @@ -680,25 +765,22 @@ class GTEST_API_ TestInfo { friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; - friend class TestCase; + friend class TestSuite; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; friend TestInfo* internal::MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - internal::TypeId fixture_class_id, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, internal::CodeLocation code_location, + internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, internal::TestFactoryBase* factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. - TestInfo(const std::string& test_case_name, - const std::string& name, + TestInfo(const std::string& test_suite_name, const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test + internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); @@ -717,19 +799,21 @@ class GTEST_API_ TestInfo { } // These fields are immutable properties of the test. - const std::string test_case_name_; // Test case name + const std::string test_suite_name_; // test suite name const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. - const internal::scoped_ptr type_param_; + const std::unique_ptr type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. - const internal::scoped_ptr value_param_; - const internal::TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled - bool matches_filter_; // True if this test matches the - // user-specified filter. + const std::unique_ptr value_param_; + internal::CodeLocation location_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True if and only if this test should run + bool is_disabled_; // True if and only if this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + bool is_in_another_shard_; // Will be run in another shard. internal::TestFactoryBase* const factory_; // The factory that creates // the test object @@ -740,90 +824,96 @@ class GTEST_API_ TestInfo { GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; -// A test case, which consists of a vector of TestInfos. +// A test suite, which consists of a vector of TestInfos. // -// TestCase is not copyable. -class GTEST_API_ TestCase { +// TestSuite is not copyable. +class GTEST_API_ TestSuite { public: - // Creates a TestCase with the given name. + // Creates a TestSuite with the given name. // - // TestCase does NOT have a default constructor. Always use this - // constructor to create a TestCase object. + // TestSuite does NOT have a default constructor. Always use this + // constructor to create a TestSuite object. // // Arguments: // - // name: name of the test case + // name: name of the test suite // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite(const char* name, const char* a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); - // Destructor of TestCase. - virtual ~TestCase(); + // Destructor of TestSuite. + virtual ~TestSuite(); - // Gets the name of the TestCase. + // Gets the name of the TestSuite. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a - // type-parameterized test case. + // type-parameterized test suite. const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; } - // Returns true if any test in this test case should run. + // Returns true if any test in this test suite should run. bool should_run() const { return should_run_; } - // Gets the number of successful tests in this test case. + // Gets the number of successful tests in this test suite. int successful_test_count() const; - // Gets the number of failed tests in this test case. + // Gets the number of skipped tests in this test suite. + int skipped_test_count() const; + + // Gets the number of failed tests in this test suite. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; - // Gets the number of disabled tests in this test case. + // Gets the number of disabled tests in this test suite. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; - // Get the number of tests in this test case that should run. + // Get the number of tests in this test suite that should run. int test_to_run_count() const; - // Gets the number of all tests in this test case. + // Gets the number of all tests in this test suite. int total_test_count() const; - // Returns true iff the test case passed. + // Returns true if and only if the test suite passed. bool Passed() const { return !Failed(); } - // Returns true iff the test case failed. + // Returns true if and only if the test suite failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } + // Gets the time of the test suite start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; // Returns the TestResult that holds test properties recorded during - // execution of SetUpTestCase and TearDownTestCase. + // execution of SetUpTestSuite and TearDownTestSuite. const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; - // Gets the (mutable) vector of TestInfos in this TestCase. + // Gets the (mutable) vector of TestInfos in this TestSuite. std::vector& test_info_list() { return test_info_list_; } - // Gets the (immutable) vector of TestInfos in this TestCase. + // Gets the (immutable) vector of TestInfos in this TestSuite. const std::vector& test_info_list() const { return test_info_list_; } @@ -835,51 +925,64 @@ class GTEST_API_ TestCase { // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } - // Adds a TestInfo to this test case. Will delete the TestInfo upon - // destruction of the TestCase object. + // Adds a TestInfo to this test suite. Will delete the TestInfo upon + // destruction of the TestSuite object. void AddTestInfo(TestInfo * test_info); - // Clears the results of all tests in this test case. + // Clears the results of all tests in this test suite. void ClearResult(); - // Clears the results of all tests in the given test case. - static void ClearTestCaseResult(TestCase* test_case) { - test_case->ClearResult(); + // Clears the results of all tests in the given test suite. + static void ClearTestSuiteResult(TestSuite* test_suite) { + test_suite->ClearResult(); } - // Runs every test in this TestCase. + // Runs every test in this TestSuite. void Run(); - // Runs SetUpTestCase() for this TestCase. This wrapper is needed - // for catching exceptions thrown from SetUpTestCase(). - void RunSetUpTestCase() { (*set_up_tc_)(); } + // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed + // for catching exceptions thrown from SetUpTestSuite(). + void RunSetUpTestSuite() { + if (set_up_tc_ != nullptr) { + (*set_up_tc_)(); + } + } - // Runs TearDownTestCase() for this TestCase. This wrapper is - // needed for catching exceptions thrown from TearDownTestCase(). - void RunTearDownTestCase() { (*tear_down_tc_)(); } + // Runs TearDownTestSuite() for this TestSuite. This wrapper is + // needed for catching exceptions thrown from TearDownTestSuite(). + void RunTearDownTestSuite() { + if (tear_down_tc_ != nullptr) { + (*tear_down_tc_)(); + } + } - // Returns true iff test passed. + // Returns true if and only if test passed. static bool TestPassed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Passed(); } - // Returns true iff test failed. + // Returns true if and only if test skipped. + static bool TestSkipped(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Skipped(); + } + + // Returns true if and only if test failed. static bool TestFailed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Failed(); } - // Returns true iff the test is disabled and will be reported in the XML - // report. + // Returns true if and only if the test is disabled and will be reported in + // the XML report. static bool TestReportableDisabled(const TestInfo* test_info) { return test_info->is_reportable() && test_info->is_disabled_; } - // Returns true iff test is disabled. + // Returns true if and only if test is disabled. static bool TestDisabled(const TestInfo* test_info) { return test_info->is_disabled_; } - // Returns true iff this test will appear in the XML report. + // Returns true if and only if this test will appear in the XML report. static bool TestReportable(const TestInfo* test_info) { return test_info->is_reportable(); } @@ -889,17 +992,17 @@ class GTEST_API_ TestCase { return test_info->should_run(); } - // Shuffles the tests in this test case. + // Shuffles the tests in this test suite. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); - // Name of the test case. + // Name of the test suite. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. - const internal::scoped_ptr type_param_; + const std::unique_ptr type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector test_info_list_; @@ -907,24 +1010,26 @@ class GTEST_API_ TestCase { // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; - // Pointer to the function that sets up the test case. - Test::SetUpTestCaseFunc set_up_tc_; - // Pointer to the function that tears down the test case. - Test::TearDownTestCaseFunc tear_down_tc_; - // True iff any test in this test case should run. + // Pointer to the function that sets up the test suite. + internal::SetUpTestSuiteFunc set_up_tc_; + // Pointer to the function that tears down the test suite. + internal::TearDownTestSuiteFunc tear_down_tc_; + // True if and only if any test in this test suite should run. bool should_run_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; - // Holds test properties recorded during execution of SetUpTestCase and - // TearDownTestCase. + // Holds test properties recorded during execution of SetUpTestSuite and + // TearDownTestSuite. TestResult ad_hoc_test_result_; - // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); + // We disallow copying TestSuites. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestSuite); }; // An Environment object is capable of setting up and tearing down an -// environment. The user should subclass this to define his own +// environment. You should subclass this to define your own // environment(s). // // An Environment object does the set-up and tear-down in virtual @@ -951,9 +1056,21 @@ class Environment { // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } }; +#if GTEST_HAS_EXCEPTIONS + +// Exception which can be thrown from TestEventListener::OnTestPartResult. +class GTEST_API_ AssertionException + : public internal::GoogleTestFailureException { + public: + explicit AssertionException(const TestPartResult& result) + : GoogleTestFailureException(result) {} +}; + +#endif // GTEST_HAS_EXCEPTIONS + // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { @@ -975,20 +1092,32 @@ class TestEventListener { // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; - // Fired before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; + // Fired before the test suite starts. + virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. + // If you want to throw an exception from this function to skip to the next + // TEST, it must be AssertionException defined above, or inherited from it. virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; - // Fired after the test case ends. - virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + // Fired after the test suite ends. + virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; @@ -1011,21 +1140,30 @@ class TestEventListener { // above. class EmptyTestEventListener : public TestEventListener { public: - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} - virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} + void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {} +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnTestStart(const TestInfo& /*test_info*/) override {} + void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {} + void OnTestEnd(const TestInfo& /*test_info*/) override {} + void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} }; // TestEventListeners lets users add listeners to track events in Google Test. @@ -1065,7 +1203,7 @@ class GTEST_API_ TestEventListeners { } private: - friend class TestCase; + friend class TestSuite; friend class TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; @@ -1106,7 +1244,7 @@ class GTEST_API_ TestEventListeners { GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; -// A UnitTest consists of a vector of TestCases. +// A UnitTest consists of a vector of TestSuites. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This @@ -1135,10 +1273,14 @@ class GTEST_API_ UnitTest { // was executed. The UnitTest object owns the string. const char* original_working_dir() const; - // Returns the TestCase object for the test that's currently running, + // Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. - const TestCase* current_test_case() const - GTEST_LOCK_EXCLUDED_(mutex_); + const TestSuite* current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_); + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); +#endif // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. @@ -1148,31 +1290,40 @@ class GTEST_API_ UnitTest { // Returns the random seed used at the start of the current test run. int random_seed() const; -#if GTEST_HAS_PARAM_TEST - // Returns the ParameterizedTestCaseRegistry object used to keep track of + // Returns the ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() + internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); -#endif // GTEST_HAS_PARAM_TEST - // Gets the number of successful test cases. - int successful_test_case_count() const; + // Gets the number of successful test suites. + int successful_test_suite_count() const; - // Gets the number of failed test cases. - int failed_test_case_count() const; + // Gets the number of failed test suites. + int failed_test_suite_count() const; - // Gets the number of all test cases. - int total_test_case_count() const; + // Gets the number of all test suites. + int total_test_suite_count() const; - // Gets the number of all test cases that contain at least one test + // Gets the number of all test suites that contain at least one test // that should run. + int test_suite_to_run_count() const; + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + int successful_test_case_count() const; + int failed_test_case_count() const; + int total_test_case_count() const; int test_case_to_run_count() const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the number of successful tests. int successful_test_count() const; + // Gets the number of skipped tests. + int skipped_test_count() const; + // Gets the number of failed tests. int failed_test_count() const; @@ -1198,19 +1349,25 @@ class GTEST_API_ UnitTest { // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; - // Returns true iff the unit test passed (i.e. all test cases passed). + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). bool Passed() const; - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). bool Failed() const; - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite* GetTestSuite(int i) const; + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* GetTestCase(int i) const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the TestResult containing information on test failures and - // properties logged outside of individual test cases. + // properties logged outside of individual test suites. const TestResult& ad_hoc_test_result() const; // Returns the list of event listeners that can be used to track events @@ -1241,25 +1398,25 @@ class GTEST_API_ UnitTest { GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from - // inside a test, to current TestCase's ad_hoc_test_result_ when invoked - // from SetUpTestCase or TearDownTestCase, or to the global property set + // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked + // from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void RecordProperty(const std::string& key, const std::string& value); - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i); + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite* GetMutableTestSuite(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } - // These classes and funcions are friends as they need to access private + // These classes and functions are friends as they need to access private // members of UnitTest. + friend class ScopedTrace; friend class Test; friend class internal::AssertHelper; - friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); @@ -1334,155 +1491,67 @@ GTEST_API_ void InitGoogleTest(int* argc, char** argv); // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); -namespace internal { - -// FormatForComparison::Format(value) formats a -// value of type ToPrint that is an operand of a comparison assertion -// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in -// the comparison, and is used to help determine the best way to -// format the value. In particular, when the value is a C string -// (char pointer) and the other operand is an STL string object, we -// want to format the C string as a string, since we know it is -// compared by value with the string object. If the value is a char -// pointer but the other operand is not an STL string object, we don't -// know whether the pointer is supposed to point to a NUL-terminated -// string, and thus want to print it as a pointer to be safe. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - -// The default case. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint& value) { - return ::testing::PrintToString(value); - } -}; - -// Array. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint* value) { - return FormatForComparison::Format(value); - } -}; - -// By default, print C string as pointers to be safe, as we don't know -// whether they actually point to a NUL-terminated string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ - template \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(static_cast(value)); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ - -// If a C string is compared with an STL string object, we know it's meant -// to point to a NUL-terminated string, and thus can print it as a string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ - template <> \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(value); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); - -#if GTEST_HAS_GLOBAL_STRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); -#endif - -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); -#endif +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +GTEST_API_ void InitGoogleTest(); -#if GTEST_HAS_STD_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); -#endif - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ +namespace internal { -// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) -// operand to be used in a failure message. The type (but not value) -// of the other operand may affect the format. This allows us to -// print a char* as a raw pointer when it is compared against another -// char* or void*, and print it as a C string when it is compared -// against an std::string object, for example. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers +// when calling EXPECT_* in a tight loop. template -std::string FormatForComparisonFailureMessage( - const T1& value, const T2& /* other_operand */) { - return FormatForComparison::Format(value); +AssertionResult CmpHelperEQFailure(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, const T2& rhs) { + return EqFailure(lhs_expression, + rhs_expression, + FormatForComparisonFailureMessage(lhs, rhs), + FormatForComparisonFailureMessage(rhs, lhs), + false); } +// This block of code defines operator==/!= +// to block lexical scope lookup. +// It prevents using invalid operator==/!= defined at namespace scope. +struct faketype {}; +inline bool operator==(faketype, faketype) { return true; } +inline bool operator!=(faketype, faketype) { return false; } + // The helper function for {ASSERT|EXPECT}_EQ. template -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4389) // Temporarily disables warning on - // signed/unsigned mismatch. -#endif - - if (expected == actual) { +AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, + const T2& rhs) { + if (lhs == rhs) { return AssertionSuccess(); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif - - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); + return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. -GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual); - -// The helper class for {ASSERT|EXPECT}_EQ. The template argument -// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() -// is a null pointer literal. The following default implementation is -// for lhs_is_null_literal being false. -template +GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs); + class EqHelper { public: // This templatized version is for the general case. - template - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); + template < + typename T1, typename T2, + // Disable this overload for cases where one argument is a pointer + // and the other is the null pointer constant. + typename std::enable_if::value || + !std::is_pointer::value>::type* = nullptr> + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, const T1& lhs, + const T2& rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } // With this overloaded version, we allow anonymous enums to be used @@ -1491,60 +1560,37 @@ class EqHelper { // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } -}; - -// This specialization is used when the first argument to ASSERT_EQ() -// is a null pointer literal, like NULL, false, or 0. -template <> -class EqHelper { - public: - // We define two overloaded versions of Compare(). The first - // version will be picked when the second argument to ASSERT_EQ() is - // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or - // EXPECT_EQ(false, a_bool). - template - static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual, - // The following line prevents this overload from being considered if T2 - // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) - // expands to Compare("", "", NULL, my_ptr), which requires a conversion - // to match the Secret* in the other overload, which would otherwise make - // this template match better. - typename EnableIf::value>::type* = 0) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } - // This version will be picked when the second argument to ASSERT_EQ() is a - // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, - // We used to have a second template parameter instead of Secret*. That - // template parameter would deduce to 'long', making this a better match - // than the first overload even without the first overload's EnableIf. - // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to - // non-pointer argument" (even a deduced integral argument), so the old - // implementation caused warnings in user code. - Secret* /* expected (NULL) */, - T* actual) { - // We already know that 'expected' is a null pointer. - return CmpHelperEQ(expected_expression, actual_expression, - static_cast(NULL), actual); + const char* lhs_expression, const char* rhs_expression, + // Handle cases where '0' is used as a null pointer literal. + std::nullptr_t /* lhs */, T* rhs) { + // We already know that 'lhs' is a null pointer. + return CmpHelperEQ(lhs_expression, rhs_expression, static_cast(nullptr), + rhs); } }; +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers +// when calling EXPECT_OP in a tight loop. +template +AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, + const T1& val1, const T2& val2, + const char* op) { + return AssertionFailure() + << "Expected: (" << expr1 << ") " << op << " (" << expr2 + << "), actual: " << FormatForComparisonFailureMessage(val1, val2) + << " vs " << FormatForComparisonFailureMessage(val2, val1); +} + // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. @@ -1555,6 +1601,7 @@ class EqHelper { // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ @@ -1562,10 +1609,7 @@ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ - return AssertionFailure() \ - << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ @@ -1589,18 +1633,18 @@ GTEST_IMPL_CMP_HELPER_(GT, >); // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); // The helper function for {ASSERT|EXPECT}_STRNE. // @@ -1622,10 +1666,10 @@ GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual); +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); // Helper function for *_STRNE on wide strings. // @@ -1683,28 +1727,28 @@ namespace internal { // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template -AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, - const char* actual_expression, - RawType expected, - RawType actual) { - const FloatingPoint lhs(expected), rhs(actual); +AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, + const char* rhs_expression, + RawType lhs_value, + RawType rhs_value) { + const FloatingPoint lhs(lhs_value), rhs(rhs_value); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } - ::std::stringstream expected_ss; - expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << expected; + ::std::stringstream lhs_ss; + lhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << lhs_value; - ::std::stringstream actual_ss; - actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << actual; + ::std::stringstream rhs_ss; + rhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << rhs_value; - return EqFailure(expected_expression, - actual_expression, - StringStreamToString(&expected_ss), - StringStreamToString(&actual_ss), + return EqFailure(lhs_expression, + rhs_expression, + StringStreamToString(&lhs_ss), + StringStreamToString(&rhs_ss), false); } @@ -1759,9 +1803,14 @@ class GTEST_API_ AssertHelper { GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; +enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; + +GTEST_API_ GTEST_ATTRIBUTE_PRINTF_(2, 3) void ColoredPrintf(GTestColor color, + const char* fmt, + ...); + } // namespace internal -#if GTEST_HAS_PARAM_TEST // The pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting @@ -1779,13 +1828,13 @@ class GTEST_API_ AssertHelper { // FooTest() { // // Can use GetParam() here. // } -// virtual ~FooTest() { +// ~FooTest() override { // // Can use GetParam() here. // } -// virtual void SetUp() { +// void SetUp() override { // // Can use GetParam() here. // } -// virtual void TearDown { +// void TearDown override { // // Can use GetParam() here. // } // }; @@ -1794,7 +1843,7 @@ class GTEST_API_ AssertHelper { // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } -// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); +// INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class WithParamInterface { @@ -1803,12 +1852,9 @@ class WithParamInterface { virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's - // constructor. This member function is non-static, even though it only - // references static data, to reduce the opportunity for incorrect uses - // like writing 'WithParamInterface::GetParam()' for a test that - // uses a fixture whose parameter type is int. - const ParamType& GetParam() const { - GTEST_CHECK_(parameter_ != NULL) + // constructor. + static const ParamType& GetParam() { + GTEST_CHECK_(parameter_ != nullptr) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; return *parameter_; @@ -1829,7 +1875,7 @@ class WithParamInterface { }; template -const T* WithParamInterface::parameter_ = NULL; +const T* WithParamInterface::parameter_ = nullptr; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. @@ -1838,10 +1884,13 @@ template class TestWithParam : public Test, public WithParamInterface { }; -#endif // GTEST_HAS_PARAM_TEST - // Macros for indicating success/failure in test code. +// Skips test in runtime. +// Skipping test aborts current function. +// Skipped tests are neither successful nor failed. +#define GTEST_SKIP() GTEST_SKIP_("Skipped") + // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has @@ -1871,6 +1920,11 @@ class TestWithParam : public Test, public WithParamInterface { // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") +// Like GTEST_FAIL(), but at the given source file location. +#define GTEST_FAIL_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kFatalFailure) + // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL @@ -1924,18 +1978,14 @@ class TestWithParam : public Test, public WithParamInterface { GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) -// Includes the auto-generated header that implements a family of -// generic predicate assertion macros. -#include "gtest/gtest_pred_impl.h" - // Macros for testing equalities and inequalities. // -// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual -// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 -// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 -// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 -// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 -// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2 +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, @@ -1957,8 +2007,8 @@ class TestWithParam : public Test, public WithParamInterface { // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // -// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to -// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// 3. {ASSERT|EXPECT}_EQ(v1, v2) is preferred to +// {ASSERT|EXPECT}_TRUE(v1 == v2), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // @@ -1969,17 +2019,15 @@ class TestWithParam : public Test, public WithParamInterface { // // Examples: // -// EXPECT_NE(5, Foo()); -// EXPECT_EQ(NULL, a_pointer); +// EXPECT_NE(Foo(), 5); +// EXPECT_EQ(a_pointer, NULL); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; -#define EXPECT_EQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) -#define EXPECT_NE(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) +#define EXPECT_EQ(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) +#define EXPECT_NE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ @@ -1989,10 +2037,8 @@ class TestWithParam : public Test, public WithParamInterface { #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) -#define GTEST_ASSERT_EQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) +#define GTEST_ASSERT_EQ(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ @@ -2047,29 +2093,29 @@ class TestWithParam : public Test, public WithParamInterface { // // These macros evaluate their arguments exactly once. -#define EXPECT_STREQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STREQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define EXPECT_STRCASEEQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASEEQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) -#define ASSERT_STREQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STREQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define ASSERT_STRCASEEQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASEEQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // -// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2): // Tests that two float values are almost equal. -// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. @@ -2079,21 +2125,21 @@ class TestWithParam : public Test, public WithParamInterface { // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. -#define EXPECT_FLOAT_EQ(expected, actual)\ +#define EXPECT_FLOAT_EQ(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) -#define EXPECT_DOUBLE_EQ(expected, actual)\ +#define EXPECT_DOUBLE_EQ(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) -#define ASSERT_FLOAT_EQ(expected, actual)\ +#define ASSERT_FLOAT_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) -#define ASSERT_DOUBLE_EQ(expected, actual)\ +#define ASSERT_DOUBLE_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ @@ -2156,6 +2202,51 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) +// Causes a trace (including the given source file path and line number, +// and the given message) to be included in every test failure message generated +// by code in the scope of the lifetime of an instance of this class. The effect +// is undone with the destruction of the instance. +// +// The message argument can be anything streamable to std::ostream. +// +// Example: +// testing::ScopedTrace trace("file.cc", 123, "message"); +// +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + + // Template version. Uses Message() to convert the values into strings. + // Slow, but flexible. + template + ScopedTrace(const char* file, int line, const T& message) { + PushTrace(file, line, (Message() << message).GetString()); + } + + // Optimize for some known types. + ScopedTrace(const char* file, int line, const char* message) { + PushTrace(file, line, message ? message : "(null)"); + } + + ScopedTrace(const char* file, int line, const std::string& message) { + PushTrace(file, line, message); + } + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + void PushTrace(const char* file, int line, std::string message); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is @@ -2167,13 +2258,17 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. +// +// Assuming that each thread maintains its own stack of traces. +// Therefore, a SCOPED_TRACE() would (correctly) only affect the +// assertions in its own thread. #define SCOPED_TRACE(message) \ - ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ - __FILE__, __LINE__, ::testing::Message() << (message)) + ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, (message)) // Compile-time assertion for type equality. -// StaticAssertTypeEq() compiles iff type1 and type2 are -// the same type. The value it returns is not interesting. +// StaticAssertTypeEq() compiles if and only if type1 and type2 +// are the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This @@ -2202,21 +2297,22 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // // to cause a compiler error. template -bool StaticAssertTypeEq() { - (void)internal::StaticAssertTypeEqHelper(); +constexpr bool StaticAssertTypeEq() noexcept { + static_assert(std::is_same::value, + "type1 and type2 are not the same type"); return true; } // Defines a test. // -// The first parameter is the name of the test case, and the second -// parameter is the name of the test within the test case. +// The first parameter is the name of the test suite, and the second +// parameter is the name of the test within the test suite. // -// The convention is to end the test case name with "Test". For -// example, a test case for the Foo class can be named FooTest. +// The convention is to end the test suite name with "Test". For +// example, a test suite for the Foo class can be named FooTest. // -// The user should put his test code between braces after using this -// macro. Example: +// Test code should appear between braces after an invocation of +// this macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; @@ -2232,28 +2328,28 @@ bool StaticAssertTypeEq() { // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. -#define GTEST_TEST(test_case_name, test_name)\ - GTEST_TEST_(test_case_name, test_name, \ - ::testing::Test, ::testing::internal::GetTestTypeId()) +#define GTEST_TEST(test_suite_name, test_name) \ + GTEST_TEST_(test_suite_name, test_name, ::testing::Test, \ + ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST -# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which -// also doubles as the test case name. The second parameter is the -// name of the test within the test case. +// also doubles as the test suite name. The second parameter is the +// name of the test within the test suite. // // A test fixture class must be declared earlier. The user should put -// his test code between braces after using this macro. Example: +// the test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: -// virtual void SetUp() { b_.AddElement(3); } +// void SetUp() override { b_.AddElement(3); } // // Foo a_; // Foo b_; @@ -2264,14 +2360,103 @@ bool StaticAssertTypeEq() { // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { -// EXPECT_EQ(0, a_.size()); -// EXPECT_EQ(1, b_.size()); +// EXPECT_EQ(a_.size(), 0); +// EXPECT_EQ(b_.size(), 1); // } - +// +// GOOGLETEST_CM0011 DO NOT DELETE #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) +// Returns a path to temporary directory. +// Tries to determine an appropriate directory for the platform. +GTEST_API_ std::string TempDir(); + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +// Dynamically registers a test with the framework. +// +// This is an advanced API only to be used when the `TEST` macros are +// insufficient. The macros should be preferred when possible, as they avoid +// most of the complexity of calling this function. +// +// The `factory` argument is a factory callable (move-constructible) object or +// function pointer that creates a new instance of the Test object. It +// handles ownership to the caller. The signature of the callable is +// `Fixture*()`, where `Fixture` is the test fixture class for the test. All +// tests registered with the same `test_suite_name` must return the same +// fixture type. This is checked at runtime. +// +// The framework will infer the fixture class from the factory and will call +// the `SetUpTestSuite` and `TearDownTestSuite` for it. +// +// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is +// undefined. +// +// Use case example: +// +// class MyFixture : public ::testing::Test { +// public: +// // All of these optional, just like in regular macro usage. +// static void SetUpTestSuite() { ... } +// static void TearDownTestSuite() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } +// }; +// +// class MyTest : public MyFixture { +// public: +// explicit MyTest(int data) : data_(data) {} +// void TestBody() override { ... } +// +// private: +// int data_; +// }; +// +// void RegisterMyTests(const std::vector& values) { +// for (int v : values) { +// ::testing::RegisterTest( +// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, +// std::to_string(v).c_str(), +// __FILE__, __LINE__, +// // Important to use the fixture type as the return type here. +// [=]() -> MyFixture* { return new MyTest(v); }); +// } +// } +// ... +// int main(int argc, char** argv) { +// std::vector values_to_test = LoadValuesFromConfig(); +// RegisterMyTests(values_to_test); +// ... +// return RUN_ALL_TESTS(); +// } +// +template +TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, + const char* type_param, const char* value_param, + const char* file, int line, Factory factory) { + using TestT = typename std::remove_pointer::type; + + class FactoryImpl : public internal::TestFactoryBase { + public: + explicit FactoryImpl(Factory f) : factory_(std::move(f)) {} + Test* CreateTest() override { return factory_(); } + + private: + Factory factory_; + }; + + return internal::MakeAndRegisterTestInfo( + test_suite_name, test_name, type_param, value_param, + internal::CodeLocation(file, line), internal::GetTypeId(), + internal::SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + internal::SuiteApiResolver::GetTearDownCaseOrSuite(file, line), + new FactoryImpl{std::move(factory)}); +} + } // namespace testing // Use this function in main() to run all tests. It returns 0 if all @@ -2288,4 +2473,6 @@ inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/test/gtest/include/gtest/gtest_pred_impl.h b/test/gtest/include/gtest/gtest_pred_impl.h index 30ae712f50..d514255c73 100644 --- a/test/gtest/include/gtest/gtest_pred_impl.h +++ b/test/gtest/include/gtest/gtest_pred_impl.h @@ -27,18 +27,18 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command +// This file is AUTOMATICALLY GENERATED on 01/02/2019 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -// Makes sure this header is not included before gtest.h. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ +#include "gtest/gtest.h" + +namespace testing { // This header implements a family of generic predicate assertion // macros: @@ -90,9 +90,10 @@ AssertionResult AssertPred1Helper(const char* pred_text, const T1& v1) { if (pred(v1)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1; + return AssertionFailure() + << pred_text << "(" << e1 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. @@ -134,11 +135,12 @@ AssertionResult AssertPred2Helper(const char* pred_text, const T2& v2) { if (pred(v1, v2)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. @@ -185,13 +187,13 @@ AssertionResult AssertPred3Helper(const char* pred_text, const T3& v3) { if (pred(v1, v2, v3)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. @@ -243,15 +245,14 @@ AssertionResult AssertPred4Helper(const char* pred_text, const T4& v4) { if (pred(v1, v2, v3, v4)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. @@ -308,17 +309,15 @@ AssertionResult AssertPred5Helper(const char* pred_text, const T5& v5) { if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ", " - << e5 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4 - << "\n" << e5 << " evaluates to " << v5; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ", " << e5 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n" + << e5 << " evaluates to " << ::testing::PrintToString(v5); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. @@ -355,4 +354,6 @@ AssertionResult AssertPred5Helper(const char* pred_text, +} // namespace testing + #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ diff --git a/test/gtest/include/gtest/gtest_prod.h b/test/gtest/include/gtest/gtest_prod.h index da80ddc6c7..e651671ebd 100644 --- a/test/gtest/include/gtest/gtest_prod.h +++ b/test/gtest/include/gtest/gtest_prod.h @@ -26,10 +26,10 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// Google C++ Testing Framework definitions useful in production code. +// Google C++ Testing and Mocking Framework definitions useful in production code. +// GOOGLETEST_CM0003 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ @@ -40,17 +40,20 @@ // // class MyClass { // private: -// void MyMethod(); -// FRIEND_TEST(MyClassTest, MyMethod); +// void PrivateMethod(); +// FRIEND_TEST(MyClassTest, PrivateMethodWorks); // }; // // class MyClassTest : public testing::Test { // // ... // }; // -// TEST_F(MyClassTest, MyMethod) { -// // Can call MyClass::MyMethod() here. +// TEST_F(MyClassTest, PrivateMethodWorks) { +// // Can call MyClass::PrivateMethod() here. // } +// +// Note: The test class must be in the same namespace as the class being tested. +// For example, putting MyClassTest in an anonymous namespace will not work. #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test diff --git a/test/gtest/include/gtest/internal/custom/README.md b/test/gtest/include/gtest/internal/custom/README.md new file mode 100644 index 0000000000..ff391fb4e2 --- /dev/null +++ b/test/gtest/include/gtest/internal/custom/README.md @@ -0,0 +1,56 @@ +# Customization Points + +The custom directory is an injection point for custom user configurations. + +## Header `gtest.h` + +### The following macros can be defined: + +* `GTEST_OS_STACK_TRACE_GETTER_` - The name of an implementation of + `OsStackTraceGetterInterface`. +* `GTEST_CUSTOM_TEMPDIR_FUNCTION_` - An override for `testing::TempDir()`. See + `testing::TempDir` for semantics and signature. + +## Header `gtest-port.h` + +The following macros can be defined: + +### Flag related macros: + +* `GTEST_FLAG(flag_name)` +* `GTEST_USE_OWN_FLAGFILE_FLAG_` - Define to 0 when the system provides its + own flagfile flag parsing. +* `GTEST_DECLARE_bool_(name)` +* `GTEST_DECLARE_int32_(name)` +* `GTEST_DECLARE_string_(name)` +* `GTEST_DEFINE_bool_(name, default_val, doc)` +* `GTEST_DEFINE_int32_(name, default_val, doc)` +* `GTEST_DEFINE_string_(name, default_val, doc)` + +### Logging: + +* `GTEST_LOG_(severity)` +* `GTEST_CHECK_(condition)` +* Functions `LogToStderr()` and `FlushInfoLog()` have to be provided too. + +### Threading: + +* `GTEST_HAS_NOTIFICATION_` - Enabled if Notification is already provided. +* `GTEST_HAS_MUTEX_AND_THREAD_LOCAL_` - Enabled if `Mutex` and `ThreadLocal` + are already provided. Must also provide `GTEST_DECLARE_STATIC_MUTEX_(mutex)` + and `GTEST_DEFINE_STATIC_MUTEX_(mutex)` +* `GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)` +* `GTEST_LOCK_EXCLUDED_(locks)` + +### Underlying library support features + +* `GTEST_HAS_CXXABI_H_` + +### Exporting API symbols: + +* `GTEST_API_` - Specifier for exported symbols. + +## Header `gtest-printers.h` + +* See documentation at `gtest/gtest-printers.h` for details on how to define a + custom printer. diff --git a/test/gtest/include/gtest/internal/custom/gtest-port.h b/test/gtest/include/gtest/internal/custom/gtest-port.h new file mode 100644 index 0000000000..cd85d956d2 --- /dev/null +++ b/test/gtest/include/gtest/internal/custom/gtest-port.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ diff --git a/test/gtest/include/gtest/internal/custom/gtest-printers.h b/test/gtest/include/gtest/internal/custom/gtest-printers.h new file mode 100644 index 0000000000..eb4467abca --- /dev/null +++ b/test/gtest/include/gtest/internal/custom/gtest-printers.h @@ -0,0 +1,42 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. +// +// This file provides an injection point for custom printers in a local +// installation of gTest. +// It will be included from gtest-printers.h and the overrides in this file +// will be visible to everyone. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ diff --git a/test/gtest/include/gtest/internal/custom/gtest.h b/test/gtest/include/gtest/internal/custom/gtest.h new file mode 100644 index 0000000000..4c8e07be23 --- /dev/null +++ b/test/gtest/include/gtest/internal/custom/gtest.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ diff --git a/test/gtest/include/gtest/internal/gtest-death-test-internal.h b/test/gtest/include/gtest/internal/gtest-death-test-internal.h index 2b3a78f5bf..68bd353061 100644 --- a/test/gtest/include/gtest/internal/gtest-death-test-internal.h +++ b/test/gtest/include/gtest/internal/gtest-death-test-internal.h @@ -27,19 +27,20 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#include "gtest/gtest-matchers.h" #include "gtest/internal/gtest-internal.h" #include +#include namespace testing { namespace internal { @@ -53,6 +54,9 @@ const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test @@ -76,7 +80,7 @@ class GTEST_API_ DeathTest { // argument is set. If the death test should be skipped, the pointer // is set to NULL; otherwise, it is set to the address of a new concrete // DeathTest object that controls the execution of the current test. - static bool Create(const char* statement, const RE* regex, + static bool Create(const char* statement, Matcher matcher, const char* file, int line, DeathTest** test); DeathTest(); virtual ~DeathTest() { } @@ -136,25 +140,50 @@ class GTEST_API_ DeathTest { GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: virtual ~DeathTestFactory() { } - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) = 0; + virtual bool Create(const char* statement, + Matcher matcher, const char* file, + int line, DeathTest** test) = 0; }; // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); + bool Create(const char* statement, Matcher matcher, + const char* file, int line, DeathTest** test) override; }; // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. GTEST_API_ bool ExitedUnsuccessfully(int exit_status); +// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads +// and interpreted as a regex (rather than an Eq matcher) for legacy +// compatibility. +inline Matcher MakeDeathTestMatcher( + ::testing::internal::RE regex) { + return ContainsRegex(regex.pattern()); +} +inline Matcher MakeDeathTestMatcher(const char* regex) { + return ContainsRegex(regex); +} +inline Matcher MakeDeathTestMatcher( + const ::std::string& regex) { + return ContainsRegex(regex); +} + +// If a Matcher is passed to EXPECT_DEATH (etc.), it's +// used directly. +inline Matcher MakeDeathTestMatcher( + Matcher matcher) { + return matcher; +} + // Traps C++ exceptions escaping statement and reports them as test // failures. Note that trapping SEH exceptions is not implemented here. # if GTEST_HAS_EXCEPTIONS @@ -182,50 +211,53 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, // ASSERT_EXIT*, and EXPECT_EXIT*. -# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - const ::testing::internal::RE& gtest_regex = (regex); \ - ::testing::internal::DeathTest* gtest_dt; \ - if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ - __FILE__, __LINE__, >est_dt)) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - if (gtest_dt != NULL) { \ - ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ - gtest_dt_ptr(gtest_dt); \ - switch (gtest_dt->AssumeRole()) { \ - case ::testing::internal::DeathTest::OVERSEE_TEST: \ - if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - break; \ - case ::testing::internal::DeathTest::EXECUTE_TEST: { \ - ::testing::internal::DeathTest::ReturnSentinel \ - gtest_sentinel(gtest_dt); \ - GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ - gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ - break; \ - } \ - default: \ - break; \ - } \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ - fail(::testing::internal::DeathTest::LastMessage()) +#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create( \ + #statement, \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != nullptr) { \ + std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \ + gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \ + : fail(::testing::internal::DeathTest::LastMessage()) // The symbol "fail" here expands to something into which a message // can be streamed. // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in -// NDEBUG mode. In this case we need the statements to be executed, the regex is -// ignored, and the macro must accept a streamed message even though the message -// is never printed. -# define GTEST_EXECUTE_STATEMENT_(statement, regex) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } else \ +// NDEBUG mode. In this case we need the statements to be executed and the macro +// must accept a streamed message even though the message is never printed. +// The regex object is not evaluated, but it is used to prevent "unused" +// warnings and to avoid an expression that doesn't compile in debug mode. +#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else if (!::testing::internal::AlwaysTrue()) { \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \ + } else \ ::testing::Message() // A class representing the parsed contents of the @@ -264,53 +296,6 @@ class InternalRunDeathTestFlag { // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); -#else // GTEST_HAS_DEATH_TEST - -// This macro is used for implementing macros such as -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where -// death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. -// -// Parameters: -// statement - A statement that a macro such as EXPECT_DEATH would test -// for program termination. This macro has to make sure this -// statement is compiled but not executed, to ensure that -// EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. -// regex - A regex that a macro such as EXPECT_DEATH would use to test -// the output of statement. This parameter has to be -// compiled but not evaluated by this macro, to ensure that -// this macro only accepts expressions that a macro such as -// EXPECT_DEATH would accept. -// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED -// and a return statement for ASSERT_DEATH_IF_SUPPORTED. -// This ensures that ASSERT_DEATH_IF_SUPPORTED will not -// compile inside functions where ASSERT_DEATH doesn't -// compile. -// -// The branch that has an always false condition is used to ensure that -// statement and regex are compiled (and thus syntactically correct) but -// never executed. The unreachable code macro protects the terminator -// statement from generating an 'unreachable code' warning in case -// statement unconditionally returns or throws. The Message constructor at -// the end allows the syntax of streaming additional messages into the -// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. -# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_LOG_(WARNING) \ - << "Death tests are not supported on this platform.\n" \ - << "Statement '" #statement "' cannot be verified."; \ - } else if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::RE::PartialMatch(".*", (regex)); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - terminator; \ - } else \ - ::testing::Message() - #endif // GTEST_HAS_DEATH_TEST } // namespace internal diff --git a/test/gtest/include/gtest/internal/gtest-filepath.h b/test/gtest/include/gtest/internal/gtest-filepath.h index 7a13b4b0de..c11b101516 100644 --- a/test/gtest/include/gtest/internal/gtest-filepath.h +++ b/test/gtest/include/gtest/internal/gtest-filepath.h @@ -27,21 +27,24 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: keith.ray@gmail.com (Keith Ray) -// // Google Test filepath utilities // // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // -// This file is #included in . +// This file is #included in gtest/internal/gtest-internal.h. // Do not include this header file separately! +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #include "gtest/internal/gtest-string.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { namespace internal { @@ -107,7 +110,7 @@ class GTEST_API_ FilePath { const FilePath& base_name, const char* extension); - // Returns true iff the path is "". + // Returns true if and only if the path is "". bool IsEmpty() const { return pathname_.empty(); } // If input name has a trailing separator character, removes it and returns @@ -203,4 +206,6 @@ class GTEST_API_ FilePath { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ diff --git a/test/gtest/include/gtest/internal/gtest-internal.h b/test/gtest/include/gtest/internal/gtest-internal.h index 0dcc3a3194..94c816a28b 100644 --- a/test/gtest/include/gtest/internal/gtest-internal.h +++ b/test/gtest/include/gtest/internal/gtest-internal.h @@ -27,13 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ @@ -55,11 +55,15 @@ #include #include #include +#include #include +#include +#include +#include #include "gtest/gtest-message.h" -#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-type-util.h" // Due to C++ preprocessor weirdness, we need double indirection to @@ -73,7 +77,9 @@ #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar -class ProtocolMessage; +// Stringifies its argument. +#define GTEST_STRINGIFY_(name) #name + namespace proto2 { class Message; } namespace testing { @@ -85,7 +91,7 @@ class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. -class UnitTest; // A collection of test cases. +class UnitTest; // A collection of test suites. template ::std::string PrintToString(const T& value); @@ -93,45 +99,29 @@ ::std::string PrintToString(const T& value); namespace internal { struct TraceInfo; // Information about a trace point. -class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest -// How many times InitGoogleTest() has been called. -GTEST_API_ extern int g_init_gtest_count; - // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; -// Two overloaded helpers for checking at compile time whether an -// expression is a null pointer literal (i.e. NULL or any 0-valued -// compile-time integral constant). Their return values have -// different sizes, so we can use sizeof() to test which version is -// picked by the compiler. These helpers have no implementations, as -// we only need their signatures. -// -// Given IsNullLiteralHelper(x), the compiler will pick the first -// version if x can be implicitly converted to Secret*, and pick the -// second version otherwise. Since Secret is a secret and incomplete -// type, the only expression a user can write that has type Secret* is -// a null pointer literal. Therefore, we know that x is a null -// pointer literal if and only if the first version is picked by the -// compiler. -char IsNullLiteralHelper(Secret* p); -char (&IsNullLiteralHelper(...))[2]; // NOLINT - -// A compile-time bool constant that is true if and only if x is a -// null pointer literal (i.e. NULL or any 0-valued compile-time -// integral constant). -#ifdef GTEST_ELLIPSIS_NEEDS_POD_ -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_IS_NULL_LITERAL_(x) false -#else -# define GTEST_IS_NULL_LITERAL_(x) \ - (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) -#endif // GTEST_ELLIPSIS_NEEDS_POD_ +// An IgnoredValue object can be implicitly constructed from ANY value. +class IgnoredValue { + struct Sink {}; + public: + // This constructor template allows any value to be implicitly + // converted to IgnoredValue. The object has no data member and + // doesn't try to remember anything about the argument. We + // deliberately omit the 'explicit' keyword in order to allow the + // conversion to be implicit. + // Disable the conversion if T already has a magical conversion operator. + // Otherwise we get ambiguity. + template ::value, + int>::type = 0> + IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit) +}; // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ std::string AppendUserMessage( @@ -139,6 +129,9 @@ GTEST_API_ std::string AppendUserMessage( #if GTEST_HAS_EXCEPTIONS +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \ +/* an exported class was derived from a class that was not exported */) + // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions // are enabled). We derive it from std::runtime_error, which is for @@ -150,26 +143,39 @@ class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { explicit GoogleTestFailureException(const TestPartResult& failure); }; -#endif // GTEST_HAS_EXCEPTIONS - -// A helper class for creating scoped traces in user programs. -class GTEST_API_ ScopedTrace { - public: - // The c'tor pushes the given source file location and message onto - // a trace stack maintained by Google Test. - ScopedTrace(const char* file, int line, const Message& message); +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275 - // The d'tor pops the info pushed by the c'tor. - // - // Note that the d'tor is not virtual in order to be efficient. - // Don't inherit from ScopedTrace! - ~ScopedTrace(); +#endif // GTEST_HAS_EXCEPTIONS - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); -} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its - // c'tor and d'tor. Therefore it doesn't - // need to be used otherwise. +namespace edit_distance { +// Returns the optimal edits to go from 'left' to 'right'. +// All edits cost the same, with replace having lower priority than +// add/remove. +// Simple implementation of the Wagner-Fischer algorithm. +// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm +enum EditType { kMatch, kAdd, kRemove, kReplace }; +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, const std::vector& right); + +// Same as above, but the input is represented as strings. +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right); + +// Create a diff of the input strings in Unified diff format. +GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context = 2); + +} // namespace edit_distance + +// Calculate the diff between 'left' and 'right' and return it in unified diff +// format. +// If not null, stores in 'total_line_count' the total number of lines found +// in left + right. +GTEST_API_ std::string DiffStrings(const std::string& left, + const std::string& right, + size_t* total_line_count); // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. @@ -183,7 +189,7 @@ class GTEST_API_ ScopedTrace { // expected_value: "5" // actual_value: "6" // -// The ignoring_case parameter is true iff the assertion is a +// The ignoring_case parameter is true if and only if the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, @@ -312,15 +318,15 @@ class FloatingPoint { // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } - // Returns true iff this is NAN (not a number). + // Returns true if and only if this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } - // Returns true iff this number is at most kMaxUlps ULP's away from - // rhs. In particular, this function: + // Returns true if and only if this number is at most kMaxUlps ULP's away + // from rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. @@ -391,7 +397,7 @@ typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different -// test fixture classes in the same test case, we need to assign +// test fixture classes in the same test suite, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare @@ -451,7 +457,7 @@ class TestFactoryBase { template class TestFactoryImpl : public TestFactoryBase { public: - virtual Test* CreateTest() { return new TestClass; } + Test* CreateTest() override { return new TestClass; } }; #if GTEST_OS_WINDOWS @@ -467,36 +473,93 @@ GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, #endif // GTEST_OS_WINDOWS -// Types of SetUpTestCase() and TearDownTestCase() functions. -typedef void (*SetUpTestCaseFunc)(); -typedef void (*TearDownTestCaseFunc)(); +// Types of SetUpTestSuite() and TearDownTestSuite() functions. +using SetUpTestSuiteFunc = void (*)(); +using TearDownTestSuiteFunc = void (*)(); + +struct CodeLocation { + CodeLocation(const std::string& a_file, int a_line) + : file(a_file), line(a_line) {} + + std::string file; + int line; +}; + +// Helper to identify which setup function for TestCase / TestSuite to call. +// Only one function is allowed, either TestCase or TestSute but not both. + +// Utility functions to help SuiteApiResolver +using SetUpTearDownSuiteFuncType = void (*)(); + +inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull( + SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) { + return a == def ? nullptr : a; +} + +template +// Note that SuiteApiResolver inherits from T because +// SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way +// SuiteApiResolver can access them. +struct SuiteApiResolver : T { + // testing::Test is only forward declared at this point. So we make it a + // dependend class for the compiler to be OK with it. + using Test = + typename std::conditional::type; + + static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both SetUpTestSuite and SetUpTestCase, please " + "make sure there is only one present at " + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } + + static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both TearDownTestSuite and TearDownTestCase," + " please make sure there is only one present at" + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } +}; // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // -// test_case_name: name of the test case +// test_suite_name: name of the test suite // name: name of the test // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param text representation of the test's value parameter, // or NULL if this is not a type-parameterized test. +// code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory); + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged @@ -505,27 +568,42 @@ GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P -// State of the definition of a type-parameterized test case. -class GTEST_API_ TypedTestCasePState { +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +// State of the definition of a type-parameterized test suite. +class GTEST_API_ TypedTestSuitePState { public: - TypedTestCasePState() : registered_(false) {} + TypedTestSuitePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true - // if the test case hasn't been registered; otherwise aborts the + // if the test suite hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { - fprintf(stderr, "%s Test %s must be defined before " - "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + fprintf(stderr, + "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); } - defined_test_names_.insert(test_name); + registered_tests_.insert( + ::std::make_pair(test_name, CodeLocation(file, line))); return true; } + bool TestExists(const std::string& test_name) const { + return registered_tests_.count(test_name) > 0; + } + + const CodeLocation& GetCodeLocation(const std::string& test_name) const { + RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); + GTEST_CHECK_(it != registered_tests_.end()); + return it->second; + } + // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. @@ -533,16 +611,25 @@ class GTEST_API_ TypedTestCasePState { const char* file, int line, const char* registered_tests); private: + typedef ::std::map RegisteredTestsMap; + bool registered_; - ::std::set defined_test_names_; + RegisteredTestsMap registered_tests_; }; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TypedTestCasePState = TypedTestSuitePState; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); - if (comma == NULL) { - return NULL; + if (comma == nullptr) { + return nullptr; } while (IsSpace(*(++comma))) {} return comma; @@ -552,7 +639,43 @@ inline const char* SkipComma(const char* str) { // the entire string if it contains no comma. inline std::string GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); - return comma == NULL ? str : std::string(str, comma); + return comma == nullptr ? str : std::string(str, comma); +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest); + +// The default argument to the template below for the case when the user does +// not provide a name generator. +struct DefaultNameGenerator { + template + static std::string GetName(int i) { + return StreamableToString(i); + } +}; + +template +struct NameGeneratorSelector { + typedef Provided type; +}; + +template +void GenerateNamesRecursively(Types0, std::vector*, int) {} + +template +void GenerateNamesRecursively(Types, std::vector* result, int i) { + result->push_back(NameGenerator::template GetName(i)); + GenerateNamesRecursively(typename Types::Tail(), result, + i + 1); +} + +template +std::vector GenerateNames() { + std::vector result; + GenerateNamesRecursively(Types(), &result, 0); + return result; } // TypeParameterizedTest::Register() @@ -566,11 +689,13 @@ template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' - // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. - static bool Register(const char* prefix, const char* case_name, - const char* test_names, int index) { + static bool Register(const char* prefix, const CodeLocation& code_location, + const char* case_name, const char* test_names, int index, + const std::vector& type_names = + GenerateNames()) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; @@ -578,19 +703,27 @@ class TypeParameterizedTest { // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( - (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" - + StreamableToString(index)).c_str(), - GetPrefixUntilComma(test_names).c_str(), + (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + + "/" + type_names[static_cast(index)]) + .c_str(), + StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), GetTypeName().c_str(), - NULL, // No value parameter. - GetTypeId(), - TestClass::SetUpTestCase, - TestClass::TearDownTestCase, + nullptr, // No value parameter. + code_location, GetTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite( + code_location.file.c_str(), code_location.line), + SuiteApiResolver::GetTearDownCaseOrSuite( + code_location.file.c_str(), code_location.line), new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. - return TypeParameterizedTest - ::Register(prefix, case_name, test_names, index + 1); + return TypeParameterizedTest::Register(prefix, + code_location, + case_name, + test_names, + index + 1, + type_names); } }; @@ -598,39 +731,63 @@ class TypeParameterizedTest { template class TypeParameterizedTest { public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/, int /*index*/) { + static bool Register(const char* /*prefix*/, const CodeLocation&, + const char* /*case_name*/, const char* /*test_names*/, + int /*index*/, + const std::vector& = + std::vector() /*type_names*/) { return true; } }; -// TypeParameterizedTestCase::Register() +// TypeParameterizedTestSuite::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template -class TypeParameterizedTestCase { +class TypeParameterizedTestSuite { public: - static bool Register(const char* prefix, const char* case_name, - const char* test_names) { + static bool Register(const char* prefix, CodeLocation code_location, + const TypedTestSuitePState* state, const char* case_name, + const char* test_names, + const std::vector& type_names = + GenerateNames()) { + std::string test_name = StripTrailingSpaces( + GetPrefixUntilComma(test_names)); + if (!state->TestExists(test_name)) { + fprintf(stderr, "Failed to get code location for test %s.%s at %s.", + case_name, test_name.c_str(), + FormatFileLocation(code_location.file.c_str(), + code_location.line).c_str()); + fflush(stderr); + posix::Abort(); + } + const CodeLocation& test_location = state->GetCodeLocation(test_name); + typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( - prefix, case_name, test_names, 0); + prefix, test_location, case_name, test_names, 0, type_names); // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase - ::Register(prefix, case_name, SkipComma(test_names)); + return TypeParameterizedTestSuite::Register(prefix, code_location, + state, case_name, + SkipComma(test_names), + type_names); } }; // The base case for the compile time recursion. template -class TypeParameterizedTestCase { +class TypeParameterizedTestSuite { public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/) { + static bool Register(const char* /*prefix*/, const CodeLocation&, + const TypedTestSuitePState* /*state*/, + const char* /*case_name*/, const char* /*test_names*/, + const std::vector& = + std::vector() /*type_names*/) { return true; } }; @@ -690,150 +847,16 @@ class GTEST_API_ Random { GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; -// Defining a variable of type CompileAssertTypesEqual will cause a -// compiler error iff T1 and T2 are different types. -template -struct CompileAssertTypesEqual; - -template -struct CompileAssertTypesEqual { -}; - -// Removes the reference from a type if it is a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::remove_reference, which is not widely available yet. -template -struct RemoveReference { typedef T type; }; // NOLINT -template -struct RemoveReference { typedef T type; }; // NOLINT - -// A handy wrapper around RemoveReference that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_REFERENCE_(T) \ - typename ::testing::internal::RemoveReference::type - -// Removes const from a type if it is a const type, otherwise leaves -// it unchanged. This is the same as tr1::remove_const, which is not -// widely available yet. -template -struct RemoveConst { typedef T type; }; // NOLINT -template -struct RemoveConst { typedef T type; }; // NOLINT - -// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above -// definition to fail to remove the const in 'const int[3]' and 'const -// char[3][4]'. The following specialization works around the bug. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; - -#if defined(_MSC_VER) && _MSC_VER < 1400 -// This is the only specialization that allows VC++ 7.1 to remove const in -// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC -// and thus needs to be conditionally compiled. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; -#endif - -// A handy wrapper around RemoveConst that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_CONST_(T) \ - typename ::testing::internal::RemoveConst::type - // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ - GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) - -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template -struct AddReference { typedef T& type; }; // NOLINT -template -struct AddReference { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GTEST_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference::type - -// Adds a reference to const on top of T as necessary. For example, -// it transforms -// -// char ==> const char& -// const char ==> const char& -// char& ==> const char& -// const char& ==> const char& -// -// The argument T must depend on some template parameters. -#define GTEST_REFERENCE_TO_CONST_(T) \ - GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) - -// ImplicitlyConvertible::value is a compile-time bool -// constant that's true iff type From can be implicitly converted to -// type To. -template -class ImplicitlyConvertible { - private: - // We need the following helper functions only for their types. - // They have no implementations. - - // MakeFrom() is an expression whose type is From. We cannot simply - // use From(), as the type From may not have a public default - // constructor. - static From MakeFrom(); - - // These two functions are overloaded. Given an expression - // Helper(x), the compiler will pick the first version if x can be - // implicitly converted to type To; otherwise it will pick the - // second version. - // - // The first version returns a value of size 1, and the second - // version returns a value of size 2. Therefore, by checking the - // size of Helper(x), which can be done at compile time, we can tell - // which version of Helper() is used, and hence whether x can be - // implicitly converted to type To. - static char Helper(To); - static char (&Helper(...))[2]; // NOLINT - - // We have to put the 'public' section after the 'private' section, - // or MSVC refuses to compile the code. - public: - // MSVC warns about implicitly converting from double to int for - // possible loss of data, so we need to temporarily disable the - // warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4244) // Temporarily disables warning 4244. - - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -# pragma warning(pop) // Restores the warning state. -#elif defined(__BORLANDC__) - // C++Builder cannot use member overload resolution during template - // instantiation. The simplest workaround is to use its C++0x type traits - // functions (C++Builder 2009 and above only). - static const bool value = __is_convertible(From, To); -#else - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -#endif // _MSV_VER -}; -template -const bool ImplicitlyConvertible::value; + typename std::remove_const::type>::type // IsAProtocolMessage::value is a compile-time bool constant that's -// true iff T is type ProtocolMessage, proto2::Message, or a subclass -// of those. +// true if and only if T is type proto2::Message or a subclass of it. template struct IsAProtocolMessage : public bool_constant< - ImplicitlyConvertible::value || - ImplicitlyConvertible::value> { -}; + std::is_convertible::value> {}; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest @@ -846,8 +869,11 @@ struct IsAProtocolMessage // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // -// Note that we look for both C::iterator and C::const_iterator. The -// reason is that C++ injects the name of a class as a member of the +// In C++11 mode we check the existence of a const_iterator and that an +// iterator is properly implemented for the container. +// +// For pre-C++11 that we look for both C::iterator and C::const_iterator. +// The reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named @@ -857,10 +883,13 @@ struct IsAProtocolMessage // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; -template -IsContainer IsContainerTest(int /* dummy */, - typename C::iterator* /* it */ = NULL, - typename C::const_iterator* /* const_it */ = NULL) { +template ().begin()), + class = decltype(::std::declval().end()), + class = decltype(++::std::declval()), + class = decltype(*::std::declval()), + class = typename C::const_iterator> +IsContainer IsContainerTest(int /* dummy */) { return 0; } @@ -868,12 +897,55 @@ typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } -// EnableIf::type is void when 'Cond' is true, and -// undefined when 'Cond' is false. To use SFINAE to make a function -// overload only apply when a particular expression is true, add -// "typename EnableIf::type* = 0" as the last parameter. -template struct EnableIf; -template<> struct EnableIf { typedef void type; }; // NOLINT +// Trait to detect whether a type T is a hash table. +// The heuristic used is that the type contains an inner type `hasher` and does +// not contain an inner type `reverse_iterator`. +// If the container is iterable in reverse, then order might actually matter. +template +struct IsHashTable { + private: + template + static char test(typename U::hasher*, typename U::reverse_iterator*); + template + static int test(typename U::hasher*, ...); + template + static char test(...); + + public: + static const bool value = sizeof(test(nullptr, nullptr)) == sizeof(int); +}; + +template +const bool IsHashTable::value; + +template (0)) == sizeof(IsContainer)> +struct IsRecursiveContainerImpl; + +template +struct IsRecursiveContainerImpl : public std::false_type {}; + +// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to +// obey the same inconsistencies as the IsContainerTest, namely check if +// something is a container is relying on only const_iterator in C++11 and +// is relying on both const_iterator and iterator otherwise +template +struct IsRecursiveContainerImpl { + using value_type = decltype(*std::declval()); + using type = + std::is_same::type>::type, + C>; +}; + +// IsRecursiveContainer is a unary compile-time predicate that +// evaluates whether C is a recursive container type. A recursive container +// type is a container type whose value_type is equal to the container type +// itself. An example for a recursive container type is +// boost::filesystem::path, whose iterator has a value_type that is equal to +// boost::filesystem::path. +template +struct IsRecursiveContainer : public IsRecursiveContainerImpl::type {}; // Utilities for native arrays. @@ -946,11 +1018,10 @@ void CopyArray(const T* from, size_t size, U* to) { // The relation between an NativeArray object (see below) and the // native array it represents. -enum RelationToSource { - kReference, // The NativeArray references the native array. - kCopy // The NativeArray makes a copy of the native array and - // owns the copy. -}; +// We use 2 different structs to allow non-copyable types to be used, as long +// as RelationToSourceReference() is passed. +struct RelationToSourceReference {}; +struct RelationToSourceCopy {}; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements @@ -968,22 +1039,23 @@ class NativeArray { typedef Element* iterator; typedef const Element* const_iterator; - // Constructs from a native array. - NativeArray(const Element* array, size_t count, RelationToSource relation) { - Init(array, count, relation); + // Constructs from a native array. References the source. + NativeArray(const Element* array, size_t count, RelationToSourceReference) { + InitRef(array, count); + } + + // Constructs from a native array. Copies the source. + NativeArray(const Element* array, size_t count, RelationToSourceCopy) { + InitCopy(array, count); } // Copy constructor. NativeArray(const NativeArray& rhs) { - Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + (this->*rhs.clone_)(rhs.array_, rhs.size_); } ~NativeArray() { - // Ensures that the user doesn't instantiate NativeArray with a - // const or reference type. - static_cast(StaticAssertTypeEqHelper()); - if (relation_to_source_ == kCopy) + if (clone_ != &NativeArray::InitRef) delete[] array_; } @@ -997,27 +1069,166 @@ class NativeArray { } private: - // Initializes this object; makes a copy of the input array if - // 'relation' is kCopy. - void Init(const Element* array, size_t a_size, RelationToSource relation) { - if (relation == kReference) { - array_ = array; - } else { - Element* const copy = new Element[a_size]; - CopyArray(array, a_size, copy); - array_ = copy; - } + static_assert(!std::is_const::value, "Type must not be const"); + static_assert(!std::is_reference::value, + "Type must not be a reference"); + + // Initializes this object with a copy of the input. + void InitCopy(const Element* array, size_t a_size) { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + size_ = a_size; + clone_ = &NativeArray::InitCopy; + } + + // Initializes this object with a reference of the input. + void InitRef(const Element* array, size_t a_size) { + array_ = array; size_ = a_size; - relation_to_source_ = relation; + clone_ = &NativeArray::InitRef; } const Element* array_; size_t size_; - RelationToSource relation_to_source_; + void (NativeArray::*clone_)(const Element*, size_t); GTEST_DISALLOW_ASSIGN_(NativeArray); }; +// Backport of std::index_sequence. +template +struct IndexSequence { + using type = IndexSequence; +}; + +// Double the IndexSequence, and one if plus_one is true. +template +struct DoubleSequence; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; + +// Backport of std::make_index_sequence. +// It uses O(ln(N)) instantiation depth. +template +struct MakeIndexSequence + : DoubleSequence::type, + N / 2>::type {}; + +template <> +struct MakeIndexSequence<0> : IndexSequence<> {}; + +// FIXME: This implementation of ElemFromList is O(1) in instantiation depth, +// but it is O(N^2) in total instantiations. Not sure if this is the best +// tradeoff, as it will make it somewhat slow to compile. +template +struct ElemFromListImpl {}; + +template +struct ElemFromListImpl { + using type = T; +}; + +// Get the Nth element from T... +// It uses O(1) instantiation depth. +template +struct ElemFromList; + +template +struct ElemFromList, T...> + : ElemFromListImpl... {}; + +template +class FlatTuple; + +template +struct FlatTupleElemBase; + +template +struct FlatTupleElemBase, I> { + using value_type = + typename ElemFromList::type, + T...>::type; + FlatTupleElemBase() = default; + explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {} + value_type value; +}; + +template +struct FlatTupleBase; + +template +struct FlatTupleBase, IndexSequence> + : FlatTupleElemBase, Idx>... { + using Indices = IndexSequence; + FlatTupleBase() = default; + explicit FlatTupleBase(T... t) + : FlatTupleElemBase, Idx>(std::move(t))... {} +}; + +// Analog to std::tuple but with different tradeoffs. +// This class minimizes the template instantiation depth, thus allowing more +// elements that std::tuple would. std::tuple has been seen to require an +// instantiation depth of more than 10x the number of elements in some +// implementations. +// FlatTuple and ElemFromList are not recursive and have a fixed depth +// regardless of T... +// MakeIndexSequence, on the other hand, it is recursive but with an +// instantiation depth of O(ln(N)). +template +class FlatTuple + : private FlatTupleBase, + typename MakeIndexSequence::type> { + using Indices = typename FlatTuple::FlatTupleBase::Indices; + + public: + FlatTuple() = default; + explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {} + + template + const typename ElemFromList::type& Get() const { + return static_cast*>(this)->value; + } + + template + typename ElemFromList::type& Get() { + return static_cast*>(this)->value; + } +}; + +// Utility functions to be called with static_assert to induce deprecation +// warnings. +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TEST_SUITE_P") +constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE_P is deprecated, please use " + "TYPED_TEST_SUITE_P") +constexpr bool TypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE is deprecated, please use " + "TYPED_TEST_SUITE") +constexpr bool TypedTestCaseIsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "REGISTER_TYPED_TEST_CASE_P is deprecated, please use " + "REGISTER_TYPED_TEST_SUITE_P") +constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TYPED_TEST_SUITE_P") +constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } + } // namespace internal } // namespace testing @@ -1037,7 +1248,10 @@ class NativeArray { #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) -// Suppresses MSVC warnings 4072 (unreachable code) for the code following +#define GTEST_SKIP_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip) + +// Suppress MSVC warning 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ @@ -1129,30 +1343,38 @@ class NativeArray { " Actual: it does.") // Expands to the name of the class that implements the given test. -#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - test_case_name##_##test_name##_Test +#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + test_suite_name##_##test_name##_Test // Helper macro for defining tests. -#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ -class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ - public:\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ - private:\ - virtual void TestBody();\ - static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ -};\ -\ -::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ - ::test_info_ =\ - ::testing::internal::MakeAndRegisterTestInfo(\ - #test_case_name, #test_name, NULL, NULL, \ - (parent_id), \ - parent_class::SetUpTestCase, \ - parent_class::TearDownTestCase, \ - new ::testing::internal::TestFactoryImpl<\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ -void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() +#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \ + static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \ + "test_suite_name must not be empty"); \ + static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \ + "test_name must not be empty"); \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public parent_class { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + \ + private: \ + virtual void TestBody(); \ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + \ + ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::test_info_ = \ + ::testing::internal::MakeAndRegisterTestInfo( \ + #test_suite_name, #test_name, nullptr, nullptr, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \ + new ::testing::internal::TestFactoryImpl); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/test/gtest/include/gtest/internal/gtest-linked_ptr.h b/test/gtest/include/gtest/internal/gtest-linked_ptr.h index b1362cd002..3602942217 100644 --- a/test/gtest/include/gtest/internal/gtest-linked_ptr.h +++ b/test/gtest/include/gtest/internal/gtest-linked_ptr.h @@ -110,7 +110,12 @@ class linked_ptr_internal { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; - while (p->next_ != ptr) p = p->next_; + while (p->next_ != ptr) { + assert(p->next_ != this && + "Trying to join() a linked ring we are already in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } p->next_ = this; next_ = ptr; } @@ -123,7 +128,12 @@ class linked_ptr_internal { if (next_ == this) return true; linked_ptr_internal const* p = next_; - while (p->next_ != this) p = p->next_; + while (p->next_ != this) { + assert(p->next_ != next_ && + "Trying to depart() a linked ring we are not in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } p->next_ = next_; return false; } diff --git a/test/gtest/include/gtest/internal/gtest-param-util-generated.h b/test/gtest/include/gtest/internal/gtest-param-util-generated.h index e80548592c..dcf90c279a 100644 --- a/test/gtest/include/gtest/internal/gtest-param-util-generated.h +++ b/test/gtest/include/gtest/internal/gtest-param-util-generated.h @@ -40,20 +40,15 @@ // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is +// by the maximum arity of the implementation of tuple which is // currently set at 10. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Forward declarations of ValuesIn(), which is implemented in @@ -79,7 +74,10 @@ class ValueArray1 { explicit ValueArray1(T1 v1) : v1_(v1) {} template - operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + operator ParamGenerator() const { + const T array[] = {static_cast(v1_)}; + return ValuesIn(array); + } private: // No implementation - assignment is unsupported. @@ -3157,9 +3155,9 @@ class ValueArray50 { // template class CartesianProductGenerator2 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) @@ -3205,7 +3203,7 @@ class CartesianProductGenerator2 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3237,7 +3235,7 @@ class CartesianProductGenerator2 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_); + current_value_.reset(new ParamType(*current1_, *current2_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3259,7 +3257,7 @@ class CartesianProductGenerator2 const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. @@ -3272,9 +3270,9 @@ class CartesianProductGenerator2 template class CartesianProductGenerator3 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) @@ -3328,7 +3326,7 @@ class CartesianProductGenerator3 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3364,7 +3362,7 @@ class CartesianProductGenerator3 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3390,7 +3388,7 @@ class CartesianProductGenerator3 const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. @@ -3404,9 +3402,9 @@ class CartesianProductGenerator3 template class CartesianProductGenerator4 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3469,7 +3467,7 @@ class CartesianProductGenerator4 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3509,8 +3507,8 @@ class CartesianProductGenerator4 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3540,7 +3538,7 @@ class CartesianProductGenerator4 const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. @@ -3555,9 +3553,9 @@ class CartesianProductGenerator4 template class CartesianProductGenerator5 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3627,7 +3625,7 @@ class CartesianProductGenerator5 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3671,8 +3669,8 @@ class CartesianProductGenerator5 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3706,7 +3704,7 @@ class CartesianProductGenerator5 const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. @@ -3723,10 +3721,10 @@ class CartesianProductGenerator5 template class CartesianProductGenerator6 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3804,7 +3802,7 @@ class CartesianProductGenerator6 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3852,8 +3850,8 @@ class CartesianProductGenerator6 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3891,7 +3889,7 @@ class CartesianProductGenerator6 const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. @@ -3909,10 +3907,10 @@ class CartesianProductGenerator6 template class CartesianProductGenerator7 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3998,7 +3996,7 @@ class CartesianProductGenerator7 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4050,8 +4048,8 @@ class CartesianProductGenerator7 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4093,7 +4091,7 @@ class CartesianProductGenerator7 const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. @@ -4112,10 +4110,10 @@ class CartesianProductGenerator7 template class CartesianProductGenerator8 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4211,7 +4209,7 @@ class CartesianProductGenerator8 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4267,8 +4265,8 @@ class CartesianProductGenerator8 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4314,7 +4312,7 @@ class CartesianProductGenerator8 const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. @@ -4334,10 +4332,10 @@ class CartesianProductGenerator8 template class CartesianProductGenerator9 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4440,7 +4438,7 @@ class CartesianProductGenerator9 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4500,9 +4498,9 @@ class CartesianProductGenerator9 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_); + *current9_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4552,7 +4550,7 @@ class CartesianProductGenerator9 const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. @@ -4573,10 +4571,10 @@ class CartesianProductGenerator9 template class CartesianProductGenerator10 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4687,7 +4685,7 @@ class CartesianProductGenerator10 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4751,9 +4749,9 @@ class CartesianProductGenerator10 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_, *current10_); + *current9_, *current10_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4807,7 +4805,7 @@ class CartesianProductGenerator10 const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. @@ -4838,8 +4836,8 @@ class CartesianProductHolder2 { CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); @@ -4860,8 +4858,8 @@ CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), @@ -4885,8 +4883,8 @@ CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), @@ -4912,8 +4910,8 @@ CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), @@ -4943,8 +4941,8 @@ CartesianProductHolder6(const Generator1& g1, const Generator2& g2, : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), @@ -4976,9 +4974,9 @@ CartesianProductHolder7(const Generator1& g1, const Generator2& g2, : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), @@ -5014,9 +5012,9 @@ CartesianProductHolder8(const Generator1& g1, const Generator2& g2, g8_(g8) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), @@ -5055,9 +5053,9 @@ CartesianProductHolder9(const Generator1& g1, const Generator2& g2, g9_(g9) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), @@ -5099,10 +5097,10 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, g9_(g9), g10_(g10) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator10( static_cast >(g1_), @@ -5138,6 +5136,4 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/test/gtest/include/gtest/internal/gtest-param-util-generated.h.pump b/test/gtest/include/gtest/internal/gtest-param-util-generated.h.pump index 009206fd31..d65086a01e 100644 --- a/test/gtest/include/gtest/internal/gtest-param-util-generated.h.pump +++ b/test/gtest/include/gtest/internal/gtest-param-util-generated.h.pump @@ -39,20 +39,15 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // and at most $maxtuple arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is +// by the maximum arity of the implementation of tuple which is // currently set at $maxtuple. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Forward declarations of ValuesIn(), which is implemented in @@ -72,29 +67,14 @@ internal::ParamGenerator ValuesIn( namespace internal { // Used in the Values() function to provide polymorphic capabilities. -template -class ValueArray1 { - public: - explicit ValueArray1(T1 v1) : v1_(v1) {} - - template - operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray1& other); - - const T1 v1_; -}; - -$range i 2..n +$range i 1..n $for i [[ $range j 1..i template <$for j, [[typename T$j]]> class ValueArray$i { public: - ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} + $if i==1 [[explicit ]]ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} template operator ParamGenerator() const { @@ -128,9 +108,9 @@ $range k 2..i template <$for j, [[typename T$j]]> class CartesianProductGenerator$i - : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > { + : public ParamGeneratorInterface< ::testing::tuple<$for j, [[T$j]]> > { public: - typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType; + typedef ::testing::tuple<$for j, [[T$j]]> ParamType; CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) : $for j, [[g$(j)_(g$j)]] {} @@ -180,7 +160,7 @@ $for k [[ virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -212,7 +192,7 @@ $for k [[ void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType($for j, [[*current$(j)_]]); + current_value_.reset(new ParamType($for j, [[*current$(j)_]])); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -237,7 +217,7 @@ $for j [[ typename ParamGenerator::iterator current$(j)_; ]] - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator$i::Iterator // No implementation - assignment is unsupported. @@ -269,8 +249,8 @@ class CartesianProductHolder$i { CartesianProductHolder$i($for j, [[const Generator$j& g$j]]) : $for j, [[g$(j)_(g$j)]] {} template <$for j, [[typename T$j]]> - operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const { - return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >( + operator ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >() const { + return ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >( new CartesianProductGenerator$i<$for j, [[T$j]]>( $for j,[[ @@ -296,6 +276,4 @@ $for j [[ } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/test/gtest/include/gtest/internal/gtest-param-util.h b/test/gtest/include/gtest/internal/gtest-param-util.h index d5e1028b0c..97533993c0 100644 --- a/test/gtest/include/gtest/internal/gtest-param-util.h +++ b/test/gtest/include/gtest/internal/gtest-param-util.h @@ -26,39 +26,61 @@ // 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. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#include + +#include #include +#include +#include +#include #include #include -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-linked_ptr.h" #include "gtest/internal/gtest-port.h" #include "gtest/gtest-printers.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { +// Input to a parameterized test name generator, describing a test parameter. +// Consists of the parameter value and the integer parameter index. +template +struct TestParamInfo { + TestParamInfo(const ParamType& a_param, size_t an_index) : + param(a_param), + index(an_index) {} + ParamType param; + size_t index; +}; + +// A builtin parameterized test name generator which returns the result of +// testing::PrintToString. +struct PrintToStringParamName { + template + std::string operator()(const TestParamInfo& info) const { + return PrintToString(info.param); + } +}; + namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// +// Utility Functions + // Outputs a message explaining invalid registration of different -// fixture class for the same test case. This may happen when +// fixture class for the same test suite. This may happen when // TEST_P macro is used to define two tests with the same name // but in different namespaces. -GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line); +GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name, + CodeLocation code_location); template class ParamGeneratorInterface; template class ParamGenerator; @@ -133,7 +155,7 @@ class ParamIterator { private: friend class ParamGenerator; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} - scoped_ptr > impl_; + std::unique_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators @@ -172,7 +194,7 @@ class ParamGenerator { iterator end() const { return iterator(impl_->End()); } private: - linked_ptr > impl_; + std::shared_ptr > impl_; }; // Generates values from a range of two comparable values. Can be used to @@ -185,12 +207,12 @@ class RangeGenerator : public ParamGeneratorInterface { RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} - virtual ~RangeGenerator() {} + ~RangeGenerator() override {} - virtual ParamIteratorInterface* Begin() const { + ParamIteratorInterface* Begin() const override { return new Iterator(this, begin_, 0, step_); } - virtual ParamIteratorInterface* End() const { + ParamIteratorInterface* End() const override { return new Iterator(this, end_, end_index_, step_); } @@ -200,20 +222,20 @@ class RangeGenerator : public ParamGeneratorInterface { Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} - virtual ~Iterator() {} + ~Iterator() override {} - virtual const ParamGeneratorInterface* BaseGenerator() const { + const ParamGeneratorInterface* BaseGenerator() const override { return base_; } - virtual void Advance() { - value_ = value_ + step_; + void Advance() override { + value_ = static_cast(value_ + step_); index_++; } - virtual ParamIteratorInterface* Clone() const { + ParamIteratorInterface* Clone() const override { return new Iterator(*this); } - virtual const T* Current() const { return &value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { + const T* Current() const override { return &value_; } + bool Equals(const ParamIteratorInterface& other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) @@ -243,7 +265,7 @@ class RangeGenerator : public ParamGeneratorInterface { const T& end, const IncrementT& step) { int end_index = 0; - for (T i = begin; i < end; i = i + step) + for (T i = begin; i < end; i = static_cast(i + step)) end_index++; return end_index; } @@ -270,12 +292,12 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} - virtual ~ValuesInIteratorRangeGenerator() {} + ~ValuesInIteratorRangeGenerator() override {} - virtual ParamIteratorInterface* Begin() const { + ParamIteratorInterface* Begin() const override { return new Iterator(this, container_.begin()); } - virtual ParamIteratorInterface* End() const { + ParamIteratorInterface* End() const override { return new Iterator(this, container_.end()); } @@ -287,16 +309,16 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} - virtual ~Iterator() {} + ~Iterator() override {} - virtual const ParamGeneratorInterface* BaseGenerator() const { + const ParamGeneratorInterface* BaseGenerator() const override { return base_; } - virtual void Advance() { + void Advance() override { ++iterator_; value_.reset(); } - virtual ParamIteratorInterface* Clone() const { + ParamIteratorInterface* Clone() const override { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ @@ -306,12 +328,11 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. - virtual const T* Current() const { - if (value_.get() == NULL) - value_.reset(new T(*iterator_)); + const T* Current() const override { + if (value_.get() == nullptr) value_.reset(new T(*iterator_)); return value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { + bool Equals(const ParamIteratorInterface& other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) @@ -334,9 +355,9 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { // A cached value of *iterator_. We keep it here to allow access by // pointer in the wrapping iterator's operator->(). // value_ needs to be mutable to be accessed in Current(). - // Use of scoped_ptr helps manage cached value's lifetime, + // Use of std::unique_ptr helps manage cached value's lifetime, // which is bound by the lifespan of the iterator itself. - mutable scoped_ptr value_; + mutable std::unique_ptr value_; }; // class ValuesInIteratorRangeGenerator::Iterator // No implementation - assignment is unsupported. @@ -345,6 +366,24 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { const ContainerType container_; }; // class ValuesInIteratorRangeGenerator +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Default parameterized test name generator, returns a string containing the +// integer test parameter index. +template +std::string DefaultParamName(const TestParamInfo& info) { + Message name_stream; + name_stream << info.index; + return name_stream.GetString(); +} + +template +void TestNotEmpty() { + static_assert(sizeof(T) == 0, "Empty arguments are not allowed."); +} +template +void TestNotEmpty(const T&) {} + // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Stores a parameter value and later creates tests parameterized with that @@ -355,7 +394,7 @@ class ParameterizedTestFactory : public TestFactoryBase { typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} - virtual Test* CreateTest() { + Test* CreateTest() override { TestClass::SetParam(¶meter_); return new TestClass(); } @@ -383,19 +422,19 @@ class TestMetaFactoryBase { // TestMetaFactory creates test factories for passing into // MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives // ownership of test factory pointer, same factory object cannot be passed -// into that method twice. But ParameterizedTestCaseInfo is going to call +// into that method twice. But ParameterizedTestSuiteInfo is going to call // it for each Test/Parameter value combination. Thus it needs meta factory // creator class. -template +template class TestMetaFactory - : public TestMetaFactoryBase { + : public TestMetaFactoryBase { public: - typedef typename TestCase::ParamType ParamType; + using ParamType = typename TestSuite::ParamType; TestMetaFactory() {} - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { - return new ParameterizedTestFactory(parameter); + TestFactoryBase* CreateTestFactory(ParamType parameter) override { + return new ParameterizedTestFactory(parameter); } private: @@ -404,216 +443,441 @@ class TestMetaFactory // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseInfoBase is a generic interface -// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// ParameterizedTestSuiteInfoBase is a generic interface +// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase // accumulates test information provided by TEST_P macro invocations -// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations // and uses that information to register all resulting test instances -// in RegisterTests method. The ParameterizeTestCaseRegistry class holds -// a collection of pointers to the ParameterizedTestCaseInfo objects +// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds +// a collection of pointers to the ParameterizedTestSuiteInfo objects // and calls RegisterTests() on each of them when asked. -class ParameterizedTestCaseInfoBase { +class ParameterizedTestSuiteInfoBase { public: - virtual ~ParameterizedTestCaseInfoBase() {} + virtual ~ParameterizedTestSuiteInfoBase() {} - // Base part of test case name for display purposes. - virtual const string& GetTestCaseName() const = 0; + // Base part of test suite name for display purposes. + virtual const std::string& GetTestSuiteName() const = 0; // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const = 0; + virtual TypeId GetTestSuiteTypeId() const = 0; // UnitTest class invokes this method to register tests in this - // test case right before running them in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. + // test suite right before running them in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. virtual void RegisterTests() = 0; protected: - ParameterizedTestCaseInfoBase() {} + ParameterizedTestSuiteInfoBase() {} private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P -// macro invocations for a particular test case and generators -// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that -// test case. It registers tests with all values generated by all +// ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test suite and generators +// obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that +// test suite. It registers tests with all values generated by all // generators when asked. -template -class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { +template +class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { public: // ParamType and GeneratorCreationFunc are private types but are required // for declarations of public methods AddTestPattern() and - // AddTestCaseInstantiation(). - typedef typename TestCase::ParamType ParamType; + // AddTestSuiteInstantiation(). + using ParamType = typename TestSuite::ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator(GeneratorCreationFunc)(); + using ParamNameGeneratorFunc = std::string(const TestParamInfo&); - explicit ParameterizedTestCaseInfo(const char* name) - : test_case_name_(name) {} + explicit ParameterizedTestSuiteInfo(const char* name, + CodeLocation code_location) + : test_suite_name_(name), code_location_(code_location) {} // Test case base name for display purposes. - virtual const string& GetTestCaseName() const { return test_case_name_; } + const std::string& GetTestSuiteName() const override { + return test_suite_name_; + } // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + TypeId GetTestSuiteTypeId() const override { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. - // test_case_name is the base name of the test case (without invocation + // test_suite_name is the base name of the test suite (without invocation // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is - // test case base name and DoBar is test base name. - void AddTestPattern(const char* test_case_name, - const char* test_base_name, + // test suite base name and DoBar is test base name. + void AddTestPattern(const char* test_suite_name, const char* test_base_name, TestMetaFactoryBase* meta_factory) { - tests_.push_back(linked_ptr(new TestInfo(test_case_name, - test_base_name, - meta_factory))); + tests_.push_back(std::shared_ptr( + new TestInfo(test_suite_name, test_base_name, meta_factory))); } - // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information // about a generator. - int AddTestCaseInstantiation(const string& instantiation_name, - GeneratorCreationFunc* func, - const char* /* file */, - int /* line */) { - instantiations_.push_back(::std::make_pair(instantiation_name, func)); + int AddTestSuiteInstantiation(const std::string& instantiation_name, + GeneratorCreationFunc* func, + ParamNameGeneratorFunc* name_func, + const char* file, int line) { + instantiations_.push_back( + InstantiationInfo(instantiation_name, func, name_func, file, line)); return 0; // Return value used only to run this method in namespace scope. } - // UnitTest class invokes this method to register tests in this test case - // test cases right before running tests in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - // UnitTest has a guard to prevent from calling this method more then once. - virtual void RegisterTests() { + // UnitTest class invokes this method to register tests in this test suite + // test suites right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more than once. + void RegisterTests() override { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { - linked_ptr test_info = *test_it; + std::shared_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { - const string& instantiation_name = gen_it->first; - ParamGenerator generator((*gen_it->second)()); + const std::string& instantiation_name = gen_it->name; + ParamGenerator generator((*gen_it->generator)()); + ParamNameGeneratorFunc* name_func = gen_it->name_func; + const char* file = gen_it->file; + int line = gen_it->line; - string test_case_name; + std::string test_suite_name; if ( !instantiation_name.empty() ) - test_case_name = instantiation_name + "/"; - test_case_name += test_info->test_case_base_name; + test_suite_name = instantiation_name + "/"; + test_suite_name += test_info->test_suite_base_name; - int i = 0; + size_t i = 0; + std::set test_param_names; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; - test_name_stream << test_info->test_base_name << "/" << i; + + std::string param_name = name_func( + TestParamInfo(*param_it, i)); + + GTEST_CHECK_(IsValidParamName(param_name)) + << "Parameterized test name '" << param_name + << "' is invalid, in " << file + << " line " << line << std::endl; + + GTEST_CHECK_(test_param_names.count(param_name) == 0) + << "Duplicate parameterized test name '" << param_name + << "', in " << file << " line " << line << std::endl; + + test_param_names.insert(param_name); + + if (!test_info->test_base_name.empty()) { + test_name_stream << test_info->test_base_name << "/"; + } + test_name_stream << param_name; MakeAndRegisterTestInfo( - test_case_name.c_str(), - test_name_stream.GetString().c_str(), - NULL, // No type parameter. - PrintToString(*param_it).c_str(), - GetTestCaseTypeId(), - TestCase::SetUpTestCase, - TestCase::TearDownTestCase, + test_suite_name.c_str(), test_name_stream.GetString().c_str(), + nullptr, // No type parameter. + PrintToString(*param_it).c_str(), code_location_, + GetTestSuiteTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + SuiteApiResolver::GetTearDownCaseOrSuite(file, line), test_info->test_meta_factory->CreateTestFactory(*param_it)); } // for param_it } // for gen_it } // for test_it - } // RegisterTests + } // RegisterTests private: // LocalTestInfo structure keeps information about a single test registered // with TEST_P macro. struct TestInfo { - TestInfo(const char* a_test_case_base_name, - const char* a_test_base_name, - TestMetaFactoryBase* a_test_meta_factory) : - test_case_base_name(a_test_case_base_name), - test_base_name(a_test_base_name), - test_meta_factory(a_test_meta_factory) {} - - const string test_case_base_name; - const string test_base_name; - const scoped_ptr > test_meta_factory; + TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) + : test_suite_base_name(a_test_suite_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const std::string test_suite_base_name; + const std::string test_base_name; + const std::unique_ptr > test_meta_factory; + }; + using TestInfoContainer = ::std::vector >; + // Records data received from INSTANTIATE_TEST_SUITE_P macros: + // + struct InstantiationInfo { + InstantiationInfo(const std::string &name_in, + GeneratorCreationFunc* generator_in, + ParamNameGeneratorFunc* name_func_in, + const char* file_in, + int line_in) + : name(name_in), + generator(generator_in), + name_func(name_func_in), + file(file_in), + line(line_in) {} + + std::string name; + GeneratorCreationFunc* generator; + ParamNameGeneratorFunc* name_func; + const char* file; + int line; }; - typedef ::std::vector > TestInfoContainer; - // Keeps pairs of - // received from INSTANTIATE_TEST_CASE_P macros. - typedef ::std::vector > - InstantiationContainer; + typedef ::std::vector InstantiationContainer; + + static bool IsValidParamName(const std::string& name) { + // Check for empty string + if (name.empty()) + return false; + + // Check for invalid characters + for (std::string::size_type index = 0; index < name.size(); ++index) { + if (!isalnum(name[index]) && name[index] != '_') + return false; + } + + return true; + } - const string test_case_name_; + const std::string test_suite_name_; + CodeLocation code_location_; TestInfoContainer tests_; InstantiationContainer instantiations_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); -}; // class ParameterizedTestCaseInfo + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo); +}; // class ParameterizedTestSuiteInfo + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +template +using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase -// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P -// macros use it to locate their corresponding ParameterizedTestCaseInfo -// descriptors. -class ParameterizedTestCaseRegistry { +// ParameterizedTestSuiteRegistry contains a map of +// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P +// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding +// ParameterizedTestSuiteInfo descriptors. +class ParameterizedTestSuiteRegistry { public: - ParameterizedTestCaseRegistry() {} - ~ParameterizedTestCaseRegistry() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - delete *it; + ParameterizedTestSuiteRegistry() {} + ~ParameterizedTestSuiteRegistry() { + for (auto& test_suite_info : test_suite_infos_) { + delete test_suite_info; } } // Looks up or creates and returns a structure containing information about - // tests and instantiations of a particular test case. - template - ParameterizedTestCaseInfo* GetTestCasePatternHolder( - const char* test_case_name, - const char* file, - int line) { - ParameterizedTestCaseInfo* typed_test_info = NULL; - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - if ((*it)->GetTestCaseName() == test_case_name) { - if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // tests and instantiations of a particular test suite. + template + ParameterizedTestSuiteInfo* GetTestSuitePatternHolder( + const char* test_suite_name, CodeLocation code_location) { + ParameterizedTestSuiteInfo* typed_test_info = nullptr; + for (auto& test_suite_info : test_suite_infos_) { + if (test_suite_info->GetTestSuiteName() == test_suite_name) { + if (test_suite_info->GetTestSuiteTypeId() != GetTypeId()) { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct - // test case setup and tear-down in this case. - ReportInvalidTestCaseType(test_case_name, file, line); + // test suite setup and tear-down in this case. + ReportInvalidTestSuiteType(test_suite_name, code_location); posix::Abort(); } else { // At this point we are sure that the object we found is of the same // type we are looking for, so we downcast it to that type // without further checks. typed_test_info = CheckedDowncastToActualType< - ParameterizedTestCaseInfo >(*it); + ParameterizedTestSuiteInfo >(test_suite_info); } break; } } - if (typed_test_info == NULL) { - typed_test_info = new ParameterizedTestCaseInfo(test_case_name); - test_case_infos_.push_back(typed_test_info); + if (typed_test_info == nullptr) { + typed_test_info = new ParameterizedTestSuiteInfo( + test_suite_name, code_location); + test_suite_infos_.push_back(typed_test_info); } return typed_test_info; } void RegisterTests() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - (*it)->RegisterTests(); + for (auto& test_suite_info : test_suite_infos_) { + test_suite_info->RegisterTests(); } } +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, CodeLocation code_location) { + return GetTestSuitePatternHolder(test_case_name, code_location); + } + +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ private: - typedef ::std::vector TestCaseInfoContainer; + using TestSuiteInfoContainer = ::std::vector; - TestCaseInfoContainer test_case_infos_; + TestSuiteInfoContainer test_suite_infos_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry); }; } // namespace internal -} // namespace testing -#endif // GTEST_HAS_PARAM_TEST +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { +// Used in the Values() function to provide polymorphic capabilities. + +template +class ValueArray { + public: + ValueArray(Ts... v) : v_{std::move(v)...} {} + + template + operator ParamGenerator() const { // NOLINT + return ValuesIn(MakeVector(MakeIndexSequence())); + } + + private: + template + std::vector MakeVector(IndexSequence) const { + return std::vector{static_cast(v_.template Get())...}; + } + + FlatTuple v_; +}; + +template +class CartesianProductGenerator + : public ParamGeneratorInterface<::std::tuple> { + public: + typedef ::std::tuple ParamType; + + CartesianProductGenerator(const std::tuple...>& g) + : generators_(g) {} + ~CartesianProductGenerator() override {} + + ParamIteratorInterface* Begin() const override { + return new Iterator(this, generators_, false); + } + ParamIteratorInterface* End() const override { + return new Iterator(this, generators_, true); + } + + private: + template + class IteratorImpl; + template + class IteratorImpl> + : public ParamIteratorInterface { + public: + IteratorImpl(const ParamGeneratorInterface* base, + const std::tuple...>& generators, bool is_end) + : base_(base), + begin_(std::get(generators).begin()...), + end_(std::get(generators).end()...), + current_(is_end ? end_ : begin_) { + ComputeCurrentValue(); + } + ~IteratorImpl() override {} + + const ParamGeneratorInterface* BaseGenerator() const override { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + void Advance() override { + assert(!AtEnd()); + // Advance the last iterator. + ++std::get(current_); + // if that reaches end, propagate that up. + AdvanceIfEnd(); + ComputeCurrentValue(); + } + ParamIteratorInterface* Clone() const override { + return new IteratorImpl(*this); + } + + const ParamType* Current() const override { return current_value_.get(); } + + bool Equals(const ParamIteratorInterface& other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const IteratorImpl* typed_other = + CheckedDowncastToActualType(&other); + + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + if (AtEnd() && typed_other->AtEnd()) return true; + + bool same = true; + bool dummy[] = { + (same = same && std::get(current_) == + std::get(typed_other->current_))...}; + (void)dummy; + return same; + } + + private: + template + void AdvanceIfEnd() { + if (std::get(current_) != std::get(end_)) return; + + bool last = ThisI == 0; + if (last) { + // We are done. Nothing else to propagate. + return; + } + + constexpr size_t NextI = ThisI - (ThisI != 0); + std::get(current_) = std::get(begin_); + ++std::get(current_); + AdvanceIfEnd(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = std::make_shared(*std::get(current_)...); + } + bool AtEnd() const { + bool at_end = false; + bool dummy[] = { + (at_end = at_end || std::get(current_) == std::get(end_))...}; + (void)dummy; + return at_end; + } + + const ParamGeneratorInterface* const base_; + std::tuple::iterator...> begin_; + std::tuple::iterator...> end_; + std::tuple::iterator...> current_; + std::shared_ptr current_value_; + }; + + using Iterator = IteratorImpl::type>; + + std::tuple...> generators_; +}; + +template +class CartesianProductHolder { + public: + CartesianProductHolder(const Gen&... g) : generators_(g...) {} + template + operator ParamGenerator<::std::tuple>() const { + return ParamGenerator<::std::tuple>( + new CartesianProductGenerator(generators_)); + } + + private: + std::tuple generators_; +}; + +} // namespace internal +} // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ diff --git a/test/gtest/include/gtest/internal/gtest-port-arch.h b/test/gtest/include/gtest/internal/gtest-port-arch.h new file mode 100644 index 0000000000..cece93dba1 --- /dev/null +++ b/test/gtest/include/gtest/internal/gtest-port-arch.h @@ -0,0 +1,107 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the GTEST_OS_* macro. +// It is separate from gtest-port.h so that custom/gtest-port.h can include it. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +# elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) +# define GTEST_OS_WINDOWS_MINGW 1 +# define GTEST_OS_WINDOWS 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(WINAPI_FAMILY) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define GTEST_OS_WINDOWS_DESKTOP 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +# define GTEST_OS_WINDOWS_PHONE 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +# define GTEST_OS_WINDOWS_RT 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) +# define GTEST_OS_WINDOWS_PHONE 1 +# define GTEST_OS_WINDOWS_TV_TITLE 1 +# else + // WINAPI_FAMILY defined but no known partition matched. + // Default to desktop. +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __OS2__ +# define GTEST_OS_OS2 1 +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +# if TARGET_OS_IPHONE +# define GTEST_OS_IOS 1 +# endif +#elif defined __DragonFly__ +# define GTEST_OS_DRAGONFLY 1 +#elif defined __FreeBSD__ +# define GTEST_OS_FREEBSD 1 +#elif defined __Fuchsia__ +# define GTEST_OS_FUCHSIA 1 +#elif defined(__GLIBC__) && defined(__FreeBSD_kernel__) +# define GTEST_OS_GNU_KFREEBSD 1 +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# if defined __ANDROID__ +# define GTEST_OS_LINUX_ANDROID 1 +# endif +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#elif defined __NetBSD__ +# define GTEST_OS_NETBSD 1 +#elif defined __OpenBSD__ +# define GTEST_OS_OPENBSD 1 +#elif defined __QNX__ +# define GTEST_OS_QNX 1 +#elif defined(__HAIKU__) +#define GTEST_OS_HAIKU 1 +#endif // __CYGWIN__ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ diff --git a/test/gtest/include/gtest/internal/gtest-port.h b/test/gtest/include/gtest/internal/gtest-port.h index ab40df1899..063fcb1083 100644 --- a/test/gtest/include/gtest/internal/gtest-port.h +++ b/test/gtest/include/gtest/internal/gtest-port.h @@ -27,34 +27,51 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan) -// // Low-level types and utilities for porting Google Test to various -// platforms. They are subject to change without notice. DO NOT USE -// THEM IN USER CODE. +// platforms. All macros ending with _ and symbols defined in an +// internal namespace are subject to change without notice. Code +// outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't +// end with _ are part of Google Test's public API and can be used by +// code outside Google Test. // // This file is fundamental to Google Test. All other Google Test source // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -#pragma GCC system_header -// The user can define the following macros in the build script to -// control Google Test's behavior. If the user doesn't define a macro -// in this list, Google Test will define it. +// Environment-describing macros +// ----------------------------- +// +// Google Test can be used in many different environments. Macros in +// this section tell Google Test what kind of environment it is being +// used in, such that Google Test can provide environment-specific +// features and implementations. +// +// Google Test tries to automatically detect the properties of its +// environment, so users usually don't need to worry about these +// macros. However, the automatic detection is not perfect. +// Sometimes it's necessary for a user to define some of the following +// macros in the build script to override Google Test's decisions. +// +// If the user doesn't define a macro in the list, Google Test will +// provide a default definition. After this header is #included, all +// macros in this list will be defined to either 1 or 0. +// +// Notes to maintainers: +// - Each macro here is a user-tweakable knob; do not grow the list +// lightly. +// - Use #if to key off these macros. Don't use #ifdef or "#if +// defined(...)", which will not work as these macros are ALWAYS +// defined. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. -// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::string, which is different to std::string). -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::wstring, which is different to std::wstring). // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that @@ -64,8 +81,6 @@ // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). -// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple -// is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". @@ -73,12 +88,6 @@ // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). -// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google -// Test's own tr1 tuple implementation should be -// used. Unused when the user sets -// GTEST_HAS_TR1_TUPLE to 0. -// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test -// is building in C++11/C++98 mode. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as @@ -86,53 +95,96 @@ // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. - -// This header defines the following utilities: +// GTEST_DEFAULT_DEATH_TEST_STYLE +// - The default value of --gtest_death_test_style. +// The legacy default has been "fast" in the open +// source version since 2008. The recommended value +// is "threadsafe", and can be set in +// custom/gtest-port.h. + +// Platform-indicating macros +// -------------------------- +// +// Macros indicating the platform on which Google Test is being used +// (a macro is defined to 1 if compiled on the given platform; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. // -// Macros indicating the current platform (defined to 1 if compiled on -// the given platform; otherwise undefined): // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_DRAGONFLY - DragonFlyBSD +// GTEST_OS_FREEBSD - FreeBSD +// GTEST_OS_FUCHSIA - Fuchsia +// GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD +// GTEST_OS_HAIKU - Haiku // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS -// GTEST_OS_IOS_SIMULATOR - iOS simulator // GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_NETBSD - NetBSD // GTEST_OS_OPENBSD - OpenBSD +// GTEST_OS_OS2 - OS/2 // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris -// GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_WINDOWS_PHONE - Windows Phone +// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT // GTEST_OS_ZOS - z/OS // -// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // -// Note that it is possible that none of the GTEST_OS_* macros are defined. +// It is possible that none of the GTEST_OS_* macros are defined. + +// Feature-indicating macros +// ------------------------- +// +// Macros indicating which Google Test features are available (a macro +// is defined to 1 if the corresponding feature is supported; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. +// +// These macros are public so that portable tests can be written. +// Such tests typically surround code using a feature with an #if +// which controls that code. For example: +// +// #if GTEST_HAS_DEATH_TEST +// EXPECT_DEATH(DoSomethingDeadly()); +// #endif // -// Macros indicating available Google Test features (defined to 1 if -// the corresponding feature is supported; otherwise undefined): -// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized -// tests) // GTEST_HAS_DEATH_TEST - death tests -// GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_IS_THREADSAFE - Google Test is thread-safe. +// GOOGLETEST_CM0007 DO NOT DELETE // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; -// the above two are mutually exclusive. -// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). +// the above RE\b(s) are mutually exclusive. + +// Misc public macros +// ------------------ +// +// GTEST_FLAG(flag_name) - references the variable corresponding to +// the given Google Test flag. + +// Internal utilities +// ------------------ +// +// The following macros and utilities are for Google Test's INTERNAL +// use only. Code outside Google Test MUST NOT USE THEM DIRECTLY. // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. @@ -141,28 +193,21 @@ // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is +// suppressed (constant conditional). +// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 +// is suppressed. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() -// - synchronization primitives. -// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above -// synchronization primitives have real implementations -// and Google Test is thread-safe; or 0 otherwise. -// -// Template meta programming: -// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. -// IteratorTraits - partial implementation of std::iterator_traits, which -// is not available in libCstd when compiled with Sun C++. -// -// Smart pointers: -// scoped_ptr - as in TR2. +// - synchronization primitives. // // Regular expressions: // RE - a simple regular expression class using the POSIX -// Extended Regular Expression syntax on UNIX-like -// platforms, or a reduced regular exception syntax on -// other platforms, including Windows. -// +// Extended Regular Expression syntax on UNIX-like platforms +// GOOGLETEST_CM0008 DO NOT DELETE +// or a reduced regular exception syntax on other +// platforms, including Windows. // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. @@ -183,7 +228,6 @@ // BiggestInt - the biggest signed integer type. // // Command-line utilities: -// GTEST_FLAG() - references a flag. // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - returns the command line as a vector of strings. @@ -193,12 +237,20 @@ // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. +// +// Deprecation warnings: +// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as +// deprecated; calling a marked function +// should generate a compiler warning #include // for isspace, etc #include // for ptrdiff_t -#include #include +#include #include +#include +#include + #ifndef _WIN32_WCE # include # include @@ -209,16 +261,29 @@ # include #endif -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" -#define GTEST_FLAG_PREFIX_ "gtest_" -#define GTEST_FLAG_PREFIX_DASH_ "gtest-" -#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" -#define GTEST_NAME_ "Google Test" -#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include +#include +#include // NOLINT + +#include "gtest/internal/gtest-port-arch.h" +#include "gtest/internal/custom/gtest-port.h" + +#if !defined(GTEST_DEV_EMAIL_) +# define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +# define GTEST_FLAG_PREFIX_ "gtest_" +# define GTEST_FLAG_PREFIX_DASH_ "gtest-" +# define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +# define GTEST_NAME_ "Google Test" +# define GTEST_PROJECT_URL_ "https://github.com/google/googletest/" +#endif // !defined(GTEST_DEV_EMAIL_) + +#if !defined(GTEST_INIT_GOOGLE_TEST_NAME_) +# define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest" +#endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_) // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ @@ -227,82 +292,73 @@ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ -// Determines the platform on which Google Test is compiled. -#ifdef __CYGWIN__ -# define GTEST_OS_CYGWIN 1 -#elif defined __SYMBIAN32__ -# define GTEST_OS_SYMBIAN 1 -#elif defined _WIN32 -# define GTEST_OS_WINDOWS 1 -# ifdef _WIN32_WCE -# define GTEST_OS_WINDOWS_MOBILE 1 -# elif defined(__MINGW__) || defined(__MINGW32__) -# define GTEST_OS_WINDOWS_MINGW 1 -# else -# define GTEST_OS_WINDOWS_DESKTOP 1 -# endif // _WIN32_WCE -#elif defined __APPLE__ -# define GTEST_OS_MAC 1 -# if TARGET_OS_IPHONE -# define GTEST_OS_IOS 1 -# if TARGET_IPHONE_SIMULATOR -# define GTEST_OS_IOS_SIMULATOR 1 -# endif -# endif -#elif defined __linux__ -# define GTEST_OS_LINUX 1 -# if defined __ANDROID__ -# define GTEST_OS_LINUX_ANDROID 1 -# endif -#elif defined __MVS__ -# define GTEST_OS_ZOS 1 -#elif defined(__sun) && defined(__SVR4) -# define GTEST_OS_SOLARIS 1 -#elif defined(_AIX) -# define GTEST_OS_AIX 1 -#elif defined(__hpux) -# define GTEST_OS_HPUX 1 -#elif defined __native_client__ -# define GTEST_OS_NACL 1 -#elif defined __OpenBSD__ -# define GTEST_OS_OPENBSD 1 -#elif defined __QNX__ -# define GTEST_OS_QNX 1 -#endif // __CYGWIN__ - -#ifndef GTEST_LANG_CXX11 -// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when -// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a -// value for __cplusplus, and recent versions of clang, gcc, and -// probably other compilers set that too in C++11 mode. -# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L -// Compiling in at least C++11 mode. -# define GTEST_LANG_CXX11 1 -# else -# define GTEST_LANG_CXX11 0 -# endif +// Macros for disabling Microsoft Visual C++ warnings. +// +// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) +// /* code that triggers warnings C4800 and C4385 */ +// GTEST_DISABLE_MSC_WARNINGS_POP_() +#if defined(_MSC_VER) +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ + __pragma(warning(push)) \ + __pragma(warning(disable: warnings)) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() \ + __pragma(warning(pop)) +#else +// Not all compilers are MSVC +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + +// Clang on Windows does not understand MSVC's pragma warning. +// We need clang-specific way to disable function deprecation warning. +#ifdef __clang__ +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") +#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + _Pragma("clang diagnostic pop") +#else +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() #endif // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. -#if !GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS_MOBILE +# include +# include +# endif +// In order to avoid having to include , use forward declaration +#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) +// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two +// separate (equivalent) structs, instead of using typedef +typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#else +// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. +// This assumption is verified by +// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. +typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#endif +#else // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include -#elif !GTEST_OS_WINDOWS_MOBILE -# include -# include -#endif +#endif // GTEST_OS_WINDOWS #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. # include // NOLINT #endif -// Defines this to true iff Google Test can use POSIX regular expressions. +// Defines this to true if and only if Google Test can use POSIX regular +// expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID // On Android, is only available starting with Gingerbread. @@ -312,7 +368,10 @@ # endif #endif -#if GTEST_HAS_POSIX_RE +#if GTEST_USES_PCRE +// The appropriate headers have already been included. + +#elif GTEST_HAS_POSIX_RE // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already @@ -334,21 +393,34 @@ // simple regex implementation instead. # define GTEST_USES_SIMPLE_RE 1 -#endif // GTEST_HAS_POSIX_RE +#endif // GTEST_USES_PCRE #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. -# if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +# if defined(_MSC_VER) && defined(_CPPUNWIND) +// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__BORLANDC__) +// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS # define _HAS_EXCEPTIONS 1 # endif // _HAS_EXCEPTIONS # define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__clang__) +// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang +// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files, +// there can be cleanups for ObjC exceptions which also need cleanups, even if +// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which +// checks for C++ exceptions starting at clang r206352, but which checked for +// cleanups prior to that. To reliably check for C++ exception availability with +// clang, check for +// __EXCEPTIONS && __has_feature(cxx_exceptions). +# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) # elif defined(__GNUC__) && __EXCEPTIONS -// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +// gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of @@ -356,7 +428,7 @@ // they are enabled unless the user tells us otherwise. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__IBMCPP__) && __EXCEPTIONS -// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +// xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to @@ -375,38 +447,21 @@ # define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. -# error "Google Test cannot be used where ::std::string isn't available." +# error "::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) -#ifndef GTEST_HAS_GLOBAL_STRING -// The user didn't tell us whether ::string is available, so we need -// to figure it out. - -# define GTEST_HAS_GLOBAL_STRING 0 - -#endif // GTEST_HAS_GLOBAL_STRING - #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. -// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring -// is available. - // Cygwin 1.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). -# define GTEST_HAS_STD_WSTRING \ - (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) +#define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + GTEST_OS_HAIKU)) #endif // GTEST_HAS_STD_WSTRING -#ifndef GTEST_HAS_GLOBAL_WSTRING -// The user didn't tell us whether ::wstring is available, so we need -// to figure it out. -# define GTEST_HAS_GLOBAL_WSTRING \ - (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) -#endif // GTEST_HAS_GLOBAL_WSTRING - // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to @@ -414,14 +469,15 @@ # ifdef _MSC_VER -# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +#ifdef _CPPRTTI // MSVC defines this macro if and only if RTTI is enabled. # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif -// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) +// Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is +// enabled. +# elif defined(__GNUC__) # ifdef __GXX_RTTI // When building against STLport with the Android NDK and with @@ -472,13 +528,16 @@ // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD -// The user didn't tell us explicitly, so we assume pthreads support is -// available on Linux and Mac. +// The user didn't tell us explicitly, so we make reasonable assumptions about +// which platforms have pthreads support. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. -# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ - || GTEST_OS_QNX) +#define GTEST_HAS_PTHREAD \ + (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \ + GTEST_OS_HAIKU) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD @@ -490,119 +549,6 @@ # include // NOLINT #endif -// Determines whether Google Test can use tr1/tuple. You can define -// this macro to 0 to prevent Google Test from using tuple (any -// feature depending on tuple with be disabled in this mode). -#ifndef GTEST_HAS_TR1_TUPLE -# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) -// STLport, provided with the Android NDK, has neither or . -# define GTEST_HAS_TR1_TUPLE 0 -# else -// The user didn't tell us not to do it, so we assume it's OK. -# define GTEST_HAS_TR1_TUPLE 1 -# endif -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether Google Test's own tr1 tuple implementation -// should be used. -#ifndef GTEST_USE_OWN_TR1_TUPLE -// The user didn't tell us, so we need to figure it out. - -// We use our own TR1 tuple if we aren't sure the user has an -// implementation of it already. At this time, libstdc++ 4.0.0+ and -// MSVC 2010 are the only mainstream standard libraries that come -// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler -// pretends to be GCC by defining __GNUC__ and friends, but cannot -// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 -// tuple in a 323 MB Feature Pack download, which we cannot assume the -// user has. QNX's QCC compiler is a modified GCC but it doesn't -// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, -// and it can be used with some compilers that define __GNUC__. -# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ - && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 -# define GTEST_ENV_HAS_TR1_TUPLE_ 1 -# endif - -// C++11 specifies that provides std::tuple. Use that if gtest is used -// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 -// can build with clang but need to use gcc4.2's libstdc++). -# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) -# define GTEST_ENV_HAS_STD_TUPLE_ 1 -# endif - -# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ -# define GTEST_USE_OWN_TR1_TUPLE 0 -# else -# define GTEST_USE_OWN_TR1_TUPLE 1 -# endif - -#endif // GTEST_USE_OWN_TR1_TUPLE - -// To avoid conditional compilation everywhere, we make it -// gtest-port.h's responsibility to #include the header implementing -// tr1/tuple. -#if GTEST_HAS_TR1_TUPLE - -# if GTEST_USE_OWN_TR1_TUPLE -# include "gtest/internal/gtest-tuple.h" -# elif GTEST_ENV_HAS_STD_TUPLE_ -# include -// C++11 puts its tuple into the ::std namespace rather than -// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. -// This causes undefined behavior, but supported compilers react in -// the way we intend. -namespace std { -namespace tr1 { -using ::std::get; -using ::std::make_tuple; -using ::std::tuple; -using ::std::tuple_element; -using ::std::tuple_size; -} -} - -# elif GTEST_OS_SYMBIAN - -// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to -// use STLport's tuple implementation, which unfortunately doesn't -// work as the copy of STLport distributed with Symbian is incomplete. -// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to -// use its own tuple implementation. -# ifdef BOOST_HAS_TR1_TUPLE -# undef BOOST_HAS_TR1_TUPLE -# endif // BOOST_HAS_TR1_TUPLE - -// This prevents , which defines -// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . -# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED -# include - -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) -// GCC 4.0+ implements tr1/tuple in the header. This does -// not conform to the TR1 spec, which requires the header to be . - -# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -// Until version 4.3.2, gcc has a bug that causes , -// which is #included by , to not compile when RTTI is -// disabled. _TR1_FUNCTIONAL is the header guard for -// . Hence the following #define is a hack to prevent -// from being included. -# define _TR1_FUNCTIONAL 1 -# include -# undef _TR1_FUNCTIONAL // Allows the user to #include - // if he chooses to. -# else -# include // NOLINT -# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 - -# else -// If the compiler is not GCC 4.0+, we assume the user is using a -// spec-conforming TR1 implementation. -# include // NOLINT -# endif // GTEST_USE_OWN_TR1_TUPLE - -#endif // GTEST_HAS_TR1_TUPLE - // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. @@ -612,8 +558,12 @@ using ::std::tuple_size; # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID -// On Android, clone() is only available on ARM starting with Gingerbread. -# if defined(__arm__) && __ANDROID_API__ >= 9 +// On Android, clone() became available at different API levels for each 32-bit +// architecture. +# if defined(__LP64__) || \ + (defined(__arm__) && __ANDROID_API__ >= 9) || \ + (defined(__mips__) && __ANDROID_API__ >= 12) || \ + (defined(__i386__) && __ANDROID_API__ >= 17) # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 @@ -632,55 +582,41 @@ using ::std::tuple_size; #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 -# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +# endif // !GTEST_OS_WINDOWS_MOBILE #endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. -// Google Test does not support death tests for VC 7.1 and earlier as -// abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ - GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD || GTEST_OS_QNX) +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \ + GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU) # define GTEST_HAS_DEATH_TEST 1 -# include // NOLINT #endif -// We don't support MSVC 7.1 with exceptions disabled now. Therefore -// all the compilers we care about are adequate for supporting -// value-parameterized tests. -#define GTEST_HAS_PARAM_TEST 1 - // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. -#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ +#if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) # define GTEST_HAS_TYPED_TEST 1 # define GTEST_HAS_TYPED_TEST_P 1 #endif -// Determines whether to support Combine(). This only makes sense when -// value-parameterized tests are enabled. The implementation doesn't -// work on Sun Studio since it doesn't understand templated conversion -// operators. -#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) -# define GTEST_HAS_COMBINE 1 -#endif - // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ - (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_AIX || GTEST_OS_OS2) // Determines whether test results can be streamed to a socket. -#if GTEST_OS_LINUX +#if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD # define GTEST_CAN_STREAM_RESULTS_ 1 #endif @@ -713,19 +649,42 @@ using ::std::tuple_size; // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) -#else +#elif defined(__clang__) +# if __has_attribute(unused) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +# endif +#endif +#ifndef GTEST_ATTRIBUTE_UNUSED_ # define GTEST_ATTRIBUTE_UNUSED_ #endif +// Use this annotation before a function that takes a printf format string. +#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) +# if defined(__MINGW_PRINTF_FORMAT) +// MinGW has two different printf implementations. Ensure the format macro +// matches the selected implementation. See +// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \ + first_to_check))) +# else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +# endif +#else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) +#endif + + // A macro to disallow operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_ASSIGN_(type)\ - void operator=(type const &) +#define GTEST_DISALLOW_ASSIGN_(type) \ + void operator=(type const &) = delete // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ - type(type const &);\ +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ + type(type const &) = delete; \ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared @@ -733,11 +692,24 @@ using ::std::tuple_size; // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; -#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +#if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else # define GTEST_MUST_USE_RESULT_ -#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC +#endif // __GNUC__ && !COMPILER_ICC + +// MS C++ compiler emits warning when a conditional expression is compile time +// constant. In some contexts this warning is false positive and needs to be +// suppressed. Use the following two macros in such cases: +// +// GTEST_INTENTIONAL_CONST_COND_PUSH_() +// while (true) { +// GTEST_INTENTIONAL_CONST_COND_POP_() +// } +# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) +# define GTEST_INTENTIONAL_CONST_COND_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally @@ -755,19 +727,39 @@ using ::std::tuple_size; #endif // GTEST_HAS_SEH -#ifdef _MSC_VER +#ifndef GTEST_IS_THREADSAFE + +#define GTEST_IS_THREADSAFE \ + (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \ + (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \ + GTEST_HAS_PTHREAD) +#endif // GTEST_IS_THREADSAFE + +// GTEST_API_ qualifies all symbols that must be exported. The definitions below +// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in +// gtest/internal/custom/gtest-port.h +#ifndef GTEST_API_ + +#ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) # elif GTEST_CREATE_SHARED_LIBRARY # define GTEST_API_ __declspec(dllexport) # endif - +#elif __GNUC__ >= 4 || defined(__clang__) +# define GTEST_API_ __attribute__((visibility ("default"))) #endif // _MSC_VER +#endif // GTEST_API_ + #ifndef GTEST_API_ # define GTEST_API_ -#endif +#endif // GTEST_API_ + +#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE +# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" +#endif // GTEST_DEFAULT_DEATH_TEST_STYLE #ifdef __GNUC__ // Ask the compiler to never inline a given function. @@ -777,16 +769,75 @@ using ::std::tuple_size; #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) -# define GTEST_HAS_CXXABI_H_ 1 -#else -# define GTEST_HAS_CXXABI_H_ 0 +#if !defined(GTEST_HAS_CXXABI_H_) +# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) +# define GTEST_HAS_CXXABI_H_ 1 +# else +# define GTEST_HAS_CXXABI_H_ 0 +# endif #endif +// A function level attribute to disable checking for use of uninitialized +// memory when built with MemorySanitizer. +#if defined(__clang__) +# if __has_feature(memory_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \ + __attribute__((no_sanitize_memory)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +# endif // __has_feature(memory_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +#endif // __clang__ + +// A function level attribute to disable AddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(address_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ + __attribute__((no_sanitize_address)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +# endif // __has_feature(address_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +#endif // __clang__ + +// A function level attribute to disable HWAddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(hwaddress_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \ + __attribute__((no_sanitize("hwaddress"))) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +# endif // __has_feature(hwaddress_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +#endif // __clang__ + +// A function level attribute to disable ThreadSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(thread_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ + __attribute__((no_sanitize_thread)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +# endif // __has_feature(thread_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +#endif // __clang__ + namespace testing { class Message; +// Legacy imports for backwards compatibility. +// New code should use std:: names directly. +using std::get; +using std::make_tuple; +using std::tuple; +using std::tuple_element; +using std::tuple_size; + namespace internal { // A secret type that Google Test users don't know about. It has no @@ -794,134 +845,30 @@ namespace internal { // Secret object, which is what we want. class Secret; -// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: -// -// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, -// content_type_names_incorrect_size); -// -// or to make sure a struct is smaller than a certain size: -// -// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -template -struct CompileAssert { -}; - -#define GTEST_COMPILE_ASSERT_(expr, msg) \ - typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ - msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ - -// Implementation details of GTEST_COMPILE_ASSERT_: -// -// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 -// elements (and thus is invalid) when the expression is false. -// -// - The simpler definition -// -// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] -// -// does not work, as gcc supports variable-length arrays whose sizes -// are determined at run-time (this is gcc's extension and not part -// of the C++ standard). As a result, gcc fails to reject the -// following code with the simple definition: -// -// int foo; -// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. +// The GTEST_COMPILE_ASSERT_ is a legacy macro used to verify that a compile +// time expression is true (in new code, use static_assert instead). For +// example, you could use it to verify the size of a static array: // -// - By using the type CompileAssert<(bool(expr))>, we ensures that -// expr is a compile-time constant. (Template arguments must be -// determined at compile-time.) +// GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, +// names_incorrect_size); // -// - The outter parentheses in CompileAssert<(bool(expr))> are necessary -// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written -// -// CompileAssert -// -// instead, these compilers will refuse to compile -// -// GTEST_COMPILE_ASSERT_(5 > 0, some_message); -// -// (They seem to think the ">" in "5 > 0" marks the end of the -// template argument list.) -// -// - The array size is (bool(expr) ? 1 : -1), instead of simply -// -// ((expr) ? 1 : -1). -// -// This is to avoid running into a bug in MS VC 7.1, which -// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. +// The second argument to the macro must be a valid C++ identifier. If the +// expression is false, compiler will issue an error containing this identifier. +#define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) -// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. -// -// This template is declared, but intentionally undefined. -template -struct StaticAssertTypeEqHelper; - -template -struct StaticAssertTypeEqHelper {}; - -#if GTEST_HAS_GLOBAL_STRING -typedef ::string string; -#else -typedef ::std::string string; -#endif // GTEST_HAS_GLOBAL_STRING - -#if GTEST_HAS_GLOBAL_WSTRING -typedef ::wstring wstring; -#elif GTEST_HAS_STD_WSTRING -typedef ::std::wstring wstring; -#endif // GTEST_HAS_GLOBAL_WSTRING +// Evaluates to the number of elements in 'array'. +#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); -// Defines scoped_ptr. - -// This implementation of scoped_ptr is PARTIAL - it only contains -// enough stuff to satisfy Google Test's need. -template -class scoped_ptr { - public: - typedef T element_type; - - explicit scoped_ptr(T* p = NULL) : ptr_(p) {} - ~scoped_ptr() { reset(); } - - T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_; } - T* get() const { return ptr_; } - - T* release() { - T* const ptr = ptr_; - ptr_ = NULL; - return ptr; - } - - void reset(T* p = NULL) { - if (p != ptr_) { - if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. - delete ptr_; - } - ptr_ = p; - } - } - - private: - T* ptr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); -}; - // Defines RE. +#if GTEST_USES_PCRE +// if used, PCRE is injected by custom/gtest-port.h +#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE + // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { @@ -933,25 +880,16 @@ class GTEST_API_ RE { // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT -#if GTEST_HAS_GLOBAL_STRING - - RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT - -#endif // GTEST_HAS_GLOBAL_STRING - RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } - // FullMatch(str, re) returns true iff regular expression re matches - // the entire str. - // PartialMatch(str, re) returns true iff regular expression re + // FullMatch(str, re) returns true if and only if regular expression re + // matches the entire str. + // PartialMatch(str, re) returns true if and only if regular expression re // matches a substring of str (including str itself). - // - // TODO(wan@google.com): make FullMatch() and PartialMatch() work - // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } @@ -959,43 +897,30 @@ class GTEST_API_ RE { return PartialMatch(str.c_str(), re); } -#if GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const ::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } - -#endif // GTEST_HAS_GLOBAL_STRING - static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); - - // We use a const char* instead of an std::string, as Google Test used to be - // used where std::string is not available. TODO(wan@google.com): change to - // std::string. const char* pattern_; bool is_valid_; -#if GTEST_USES_POSIX_RE +# if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). -#else // GTEST_USES_SIMPLE_RE +# else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); -#endif +# endif GTEST_DISALLOW_ASSIGN_(RE); }; +#endif // GTEST_USES_PCRE + // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); @@ -1037,13 +962,18 @@ class GTEST_API_ GTestLog { GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; -#define GTEST_LOG_(severity) \ +#if !defined(GTEST_LOG_) + +# define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} -inline void FlushInfoLog() { fflush(NULL); } +inline void FlushInfoLog() { fflush(nullptr); } +#endif // !defined(GTEST_LOG_) + +#if !defined(GTEST_CHECK_) // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition @@ -1058,12 +988,13 @@ inline void FlushInfoLog() { fflush(NULL); } // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. -#define GTEST_CHECK_(condition) \ +# define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " +#endif // !defined(GTEST_CHECK_) // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this @@ -1075,6 +1006,26 @@ inline void FlushInfoLog() { fflush(NULL); } GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error +// Transforms "T" into "const T&" according to standard reference collapsing +// rules (this is only needed as a backport for C++98 compilers that do not +// support reference collapsing). Specifically, it transforms: +// +// char ==> const char& +// const char ==> const char& +// char& ==> char& +// const char& ==> const char& +// +// Note that the non-const reference will not have "const" added. This is +// standard, and necessary so that "T" can always bind to "const T&". +template +struct ConstRef { typedef const T& type; }; +template +struct ConstRef { typedef T& type; }; + +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + typename ::testing::internal::ConstRef::type + // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in @@ -1125,14 +1076,16 @@ inline To DownCast_(From* f) { // so we only accept pointers // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. + GTEST_INTENTIONAL_CONST_COND_PUSH_() if (false) { - const To to = NULL; - ::testing::internal::ImplicitCast_(to); + GTEST_INTENTIONAL_CONST_COND_POP_() + const To to = nullptr; + ::testing::internal::ImplicitCast_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! - GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); + GTEST_CHECK_(f == nullptr || dynamic_cast(f) != nullptr); #endif return static_cast(f); } @@ -1146,6 +1099,11 @@ template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); +#endif + +#if GTEST_HAS_DOWNCAST_ + return ::down_cast(base); +#elif GTEST_HAS_RTTI return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. @@ -1166,34 +1124,45 @@ GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION +// Returns the size (in bytes) of a file. +GTEST_API_ size_t GetFileSize(FILE* file); +// Reads the entire content of a file as a string. +GTEST_API_ std::string ReadEntireFile(FILE* file); -#if GTEST_HAS_DEATH_TEST +// All command line arguments. +GTEST_API_ std::vector GetArgvs(); -const ::std::vector& GetInjectableArgvs(); -void SetInjectableArgvs(const ::std::vector* - new_argvs); +#if GTEST_HAS_DEATH_TEST -// A copy of all command line arguments. Set by InitGoogleTest(). -extern ::std::vector g_argvs; +std::vector GetInjectableArgvs(); +// Deprecated: pass the args vector by value instead. +void SetInjectableArgvs(const std::vector* new_argvs); +void SetInjectableArgvs(const std::vector& new_argvs); +void ClearInjectableArgvs(); #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. - -#if GTEST_HAS_PTHREAD - -// Sleeps for (roughly) n milli-seconds. This function is only for -// testing Google Test's own constructs. Don't use it in user tests, -// either directly or indirectly. +#if GTEST_IS_THREADSAFE +# if GTEST_HAS_PTHREAD +// Sleeps for (roughly) n milliseconds. This function is only for testing +// Google Test's own constructs. Don't use it in user tests, either +// directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; - nanosleep(&time, NULL); + nanosleep(&time, nullptr); } +# endif // GTEST_HAS_PTHREAD +# if GTEST_HAS_NOTIFICATION_ +// Notification has already been imported into the namespace. +// Nothing to do here. + +# elif GTEST_HAS_PTHREAD // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. @@ -1203,7 +1172,7 @@ inline void SleepMilliseconds(int n) { class Notification { public: Notification() : notified_(false) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); } ~Notification() { pthread_mutex_destroy(&mutex_); @@ -1237,6 +1206,63 @@ class Notification { GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +GTEST_API_ void SleepMilliseconds(int n); + +// Provides leak-safe Windows kernel handle ownership. +// Used in death tests and in threading support. +class GTEST_API_ AutoHandle { + public: + // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to + // avoid including in this header file. Including is + // undesirable because it defines a lot of symbols and macros that tend to + // conflict with client code. This assumption is verified by + // WindowsTypesTest.HANDLEIsVoidStar. + typedef void* Handle; + AutoHandle(); + explicit AutoHandle(Handle handle); + + ~AutoHandle(); + + Handle Get() const; + void Reset(); + void Reset(Handle handle); + + private: + // Returns true if and only if the handle is a valid handle object that can be + // closed. + bool IsCloseable() const; + + Handle handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class GTEST_API_ Notification { + public: + Notification(); + void Notify(); + void WaitForNotification(); + + private: + AutoHandle event_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; +# endif // GTEST_HAS_NOTIFICATION_ + +// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD +// defined, but we don't want to use MinGW's pthreads implementation, which +// has conformance problems with some versions of the POSIX standard. +# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW + // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a @@ -1256,7 +1282,7 @@ class ThreadWithParamBase { // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast(thread)->Run(); - return NULL; + return nullptr; } // Helper class for testing Google Test's multi-threading constructs. @@ -1274,10 +1300,9 @@ extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { template class ThreadWithParam : public ThreadWithParamBase { public: - typedef void (*UserThreadFunc)(T); + typedef void UserThreadFunc(T); - ThreadWithParam( - UserThreadFunc func, T param, Notification* thread_can_start) + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), @@ -1286,54 +1311,321 @@ class ThreadWithParam : public ThreadWithParamBase { // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( - pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + pthread_create(&thread_, nullptr, &ThreadFuncWithCLinkage, base)); } - ~ThreadWithParam() { Join(); } + ~ThreadWithParam() override { Join(); } void Join() { if (!finished_) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr)); finished_ = true; } } - virtual void Run() { - if (thread_can_start_ != NULL) - thread_can_start_->WaitForNotification(); + void Run() override { + if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification(); func_(param_); } private: - const UserThreadFunc func_; // User-supplied thread function. + UserThreadFunc* const func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; - bool finished_; // true iff we know that the thread function has finished. + bool finished_; // true if and only if we know that the thread function has + // finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; +# endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD || + // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ + +# if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ +// Mutex and ThreadLocal have already been imported into the namespace. +// Nothing to do here. -// MutexBase and Mutex implement mutex on pthreads-based platforms. They -// are used in conjunction with class MutexLock: +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +// Mutex implements mutex on Windows platforms. It is used in conjunction +// with class MutexLock: // // Mutex mutex; // ... -// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end -// // of the current scope. -// -// MutexBase implements behavior for both statically and dynamically -// allocated mutexes. Do not use MutexBase directly. Instead, write -// the following to define a static mutex: +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the +// // end of the current scope. // +// A static Mutex *must* be defined or declared using one of the following +// macros: // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// (A non-static Mutex is defined/declared in the usual way). +class GTEST_API_ Mutex { + public: + enum MutexType { kStatic = 0, kDynamic = 1 }; + // We rely on kStaticMutex being 0 as it is to what the linker initializes + // type_ in static mutexes. critical_section_ will be initialized lazily + // in ThreadSafeLazyInit(). + enum StaticConstructorSelector { kStaticMutex = 0 }; + + // This constructor intentionally does nothing. It relies on type_ being + // statically initialized to 0 (effectively setting it to kStatic) and on + // ThreadSafeLazyInit() to lazily initialize the rest of the members. + explicit Mutex(StaticConstructorSelector /*dummy*/) {} + + Mutex(); + ~Mutex(); + + void Lock(); + + void Unlock(); + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld(); + + private: + // Initializes owner_thread_id_ and critical_section_ in static mutexes. + void ThreadSafeLazyInit(); + + // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503, + // we assume that 0 is an invalid value for thread IDs. + unsigned int owner_thread_id_; + + // For static mutexes, we rely on these members being initialized to zeros + // by the linker. + MutexType type_; + long critical_section_init_phase_; // NOLINT + GTEST_CRITICAL_SECTION* critical_section_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + Mutex* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Base class for ValueHolder. Allows a caller to hold and delete a value +// without knowing its type. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Provides a way for a thread to send notifications to a ThreadLocal +// regardless of its parameter type. +class ThreadLocalBase { + public: + // Creates a new ValueHolder object holding a default value passed to + // this ThreadLocal's constructor and returns it. It is the caller's + // responsibility not to call this when the ThreadLocal instance already + // has a value on the current thread. + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; + + protected: + ThreadLocalBase() {} + virtual ~ThreadLocalBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase); +}; + +// Maps a thread to a set of ThreadLocals that have values instantiated on that +// thread and notifies them when the thread exits. A ThreadLocal instance is +// expected to persist until all threads it has values on have terminated. +class GTEST_API_ ThreadLocalRegistry { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance); + + // Invoked when a ThreadLocal instance is destroyed. + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance); +}; + +class GTEST_API_ ThreadWithParamBase { + public: + void Join(); + + protected: + class Runnable { + public: + virtual ~Runnable() {} + virtual void Run() = 0; + }; + + ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); + virtual ~ThreadWithParamBase(); + + private: + AutoHandle thread_; +}; + +// Helper class for testing Google Test's multi-threading constructs. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void UserThreadFunc(T); + + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) + : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { + } + virtual ~ThreadWithParam() {} + + private: + class RunnableImpl : public Runnable { + public: + RunnableImpl(UserThreadFunc* func, T param) + : func_(func), + param_(param) { + } + virtual ~RunnableImpl() {} + virtual void Run() { + func_(param_); + } + + private: + UserThreadFunc* const func_; + const T param_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); + }; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// Implements thread-local storage on Windows systems. // -// You can forward declare a static mutex like this: +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. // -// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); // -// To create a dynamic mutex, just define an object of type Mutex. +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// The users of a TheadLocal instance have to make sure that all but one +// threads (including the main one) using that instance have exited before +// destroying it. Otherwise, the per-thread objects managed for them by the +// ThreadLocal instance are not guaranteed to be destroyed on all platforms. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal : public ThreadLocalBase { + public: + ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : default_factory_(new InstanceValueHolderFactory(value)) {} + + ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of T. Can be deleted via its base class without the caller + // knowing the type of T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + ValueHolder() : value_() {} + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + + T* GetOrCreateValue() const { + return static_cast( + ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); + } + + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { + return default_factory_->MakeNewHolder(); + } + + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + virtual ValueHolder* MakeNewHolder() const { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + + std::unique_ptr default_factory_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# elif GTEST_HAS_PTHREAD + +// MutexBase and Mutex implement mutex on pthreads-based platforms. class MutexBase { public: // Acquires this mutex. @@ -1378,8 +1670,8 @@ class MutexBase { }; // Forward-declares a static mutex. -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::MutexBase mutex +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, @@ -1387,15 +1679,15 @@ class MutexBase { // particular, the owner_ field (a pthread_t) is not explicitly initialized. // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0} // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); has_owner_ = false; } ~Mutex() { @@ -1406,9 +1698,11 @@ class Mutex : public MutexBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; -// We cannot name this class MutexLock as the ctor declaration would +// We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some -// platforms. Hence the typedef trick below. +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) @@ -1442,41 +1736,14 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) { } // Implements thread-local storage on pthreads-based systems. -// -// // Thread 1 -// ThreadLocal tl(100); // 100 is the default value for each thread. -// -// // Thread 2 -// tl.set(150); // Changes the value for thread 2 only. -// EXPECT_EQ(150, tl.get()); -// -// // Thread 1 -// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. -// tl.set(200); -// EXPECT_EQ(200, tl.get()); -// -// The template type argument T must have a public copy constructor. -// In addition, the default ThreadLocal constructor requires T to have -// a public default constructor. -// -// An object managed for a thread by a ThreadLocal instance is deleted -// when the thread exits. Or, if the ThreadLocal instance dies in -// that thread, when the ThreadLocal dies. It's the user's -// responsibility to ensure that all other threads using a ThreadLocal -// have exited when it dies, or the per-thread objects for those -// threads will not be deleted. -// -// Google Test only uses global ThreadLocal objects. That means they -// will die after main() has returned. Therefore, no per-thread -// object managed by Google Test will be leaked as long as all threads -// using Google Test have exited when main() returns. template -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: - ThreadLocal() : key_(CreateKey()), - default_() {} - explicit ThreadLocal(const T& value) : key_(CreateKey()), - default_(value) {} + ThreadLocal() + : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : key_(CreateKey()), + default_factory_(new InstanceValueHolderFactory(value)) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. @@ -1496,6 +1763,7 @@ class ThreadLocal { // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: + ValueHolder() : value_() {} explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } @@ -1517,26 +1785,58 @@ class ThreadLocal { T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast(pthread_getspecific(key_)); - if (holder != NULL) { + if (holder != nullptr) { return CheckedDowncastToActualType(holder)->pointer(); } - ValueHolder* const new_holder = new ValueHolder(default_); + ValueHolder* const new_holder = default_factory_->MakeNewHolder(); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + virtual ValueHolder* MakeNewHolder() const { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; - const T default_; // The default value for each thread. + std::unique_ptr default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; -# define GTEST_IS_THREADSAFE 1 +# endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ -#else // GTEST_HAS_PTHREAD +#else // GTEST_IS_THREADSAFE // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where @@ -1556,6 +1856,11 @@ class Mutex { # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT @@ -1564,7 +1869,7 @@ class GTestMutexLock { typedef GTestMutexLock MutexLock; template -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} @@ -1576,68 +1881,14 @@ class ThreadLocal { T value_; }; -// The above synchronization primitives have dummy implementations. -// Therefore Google Test is not thread-safe. -# define GTEST_IS_THREADSAFE 0 - -#endif // GTEST_HAS_PTHREAD +#endif // GTEST_IS_THREADSAFE // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. GTEST_API_ size_t GetThreadCount(); -// Passing non-POD classes through ellipsis (...) crashes the ARM -// compiler and generates a warning in Sun Studio. The Nokia Symbian -// and the IBM XL C/C++ compiler try to instantiate a copy constructor -// for objects passed through ellipsis (...), failing for uncopyable -// objects. We define this to ensure that only POD is passed through -// ellipsis on these systems. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_ELLIPSIS_NEEDS_POD_ 1 -#else -# define GTEST_CAN_COMPARE_NULL 1 -#endif - -// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between -// const T& and const T* in a function template. These compilers -// _can_ decide between class template specializations for T and T*, -// so a tr1::type_traits-like is_pointer works. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) -# define GTEST_NEEDS_IS_POINTER_ 1 -#endif - -template -struct bool_constant { - typedef bool_constant type; - static const bool value = bool_value; -}; -template const bool bool_constant::value; - -typedef bool_constant false_type; -typedef bool_constant true_type; - -template -struct is_pointer : public false_type {}; - -template -struct is_pointer : public true_type {}; - -template -struct IteratorTraits { - typedef typename Iterator::value_type value_type; -}; - -template -struct IteratorTraits { - typedef T value_type; -}; - -template -struct IteratorTraits { - typedef T value_type; -}; +template +using bool_constant = std::integral_constant; #if GTEST_OS_WINDOWS # define GTEST_PATH_SEP_ "\\" @@ -1690,6 +1941,13 @@ inline char ToUpper(char ch) { return static_cast(toupper(static_cast(ch))); } +inline std::string StripTrailingSpaces(std::string str) { + std::string::iterator it = str.end(); + while (it != str.begin() && IsSpace(*--it)) + it = str.erase(it); + return str; +} + // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these @@ -1753,11 +2011,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } // Functions deprecated by MSVC 8.0. -#ifdef _MSC_VER -// Temporarily disable warning 4996 (deprecated function). -# pragma warning(push) -# pragma warning(disable:4996) -#endif +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); @@ -1767,7 +2021,7 @@ inline const char* StrNCpy(char* dest, const char* src, size_t n) { // StrError() aren't needed on Windows CE at this time and thus not // defined there. -#if !GTEST_OS_WINDOWS_MOBILE +#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { @@ -1791,30 +2045,29 @@ inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT // We are on Windows CE, which has no environment variables. - return NULL; + static_cast(name); // To prevent 'unused argument' warning. + return nullptr; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); - return (env != NULL && env[0] != '\0') ? env : NULL; + return (env != nullptr && env[0] != '\0') ? env : nullptr; #else return getenv(name); #endif } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif +GTEST_DISABLE_MSC_DEPRECATED_POP_() #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. -void Abort(); +[[noreturn]] void Abort(); #else -inline void Abort() { abort(); } +[[noreturn]] inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix @@ -1824,13 +2077,12 @@ inline void Abort() { abort(); } // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. -#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +#if _MSC_VER && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. # define GTEST_SNPRINTF_(buffer, size, format, ...) \ _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) -// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't -// complain about _snprintf. +// Windows CE does not define _snprintf_s # define GTEST_SNPRINTF_ _snprintf #else # define GTEST_SNPRINTF_ snprintf @@ -1907,42 +2159,73 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. -#define GTEST_FLAG(name) FLAGS_gtest_##name +#if !defined(GTEST_FLAG) +# define GTEST_FLAG(name) FLAGS_gtest_##name +#endif // !defined(GTEST_FLAG) + +#if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) +# define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 +#endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) + +#if !defined(GTEST_DECLARE_bool_) +# define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver // Macros for declaring flags. -#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) -#define GTEST_DECLARE_int32_(name) \ +# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +# define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) -#define GTEST_DECLARE_string_(name) \ +# define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. -#define GTEST_DEFINE_bool_(name, default_val, doc) \ +# define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_int32_(name, default_val, doc) \ +# define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_string_(name, default_val, doc) \ +# define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) +#endif // !defined(GTEST_DECLARE_bool_) + // Thread annotations -#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) -#define GTEST_LOCK_EXCLUDED_(locks) +#if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) +# define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) +# define GTEST_LOCK_EXCLUDED_(locks) +#endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. -// TODO(chandlerc): Find a better way to refactor flag and environment parsing -// out of both gtest-port.cc and gtest.cc to avoid exporting this utility -// function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +std::string OutputFlagAlsoCheckEnvVar(); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing +#if !defined(GTEST_INTERNAL_DEPRECATED) + +// Internal Macro to mark an API deprecated, for googletest usage only +// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or +// GTEST_INTERNAL_DEPRECATED(message) myFunction(); Every usage of +// a deprecated entity will trigger a warning when compiled with +// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler). +// For msvc /W3 option will need to be used +// Note that for 'other' compilers this macro evaluates to nothing to prevent +// compilations errors. +#if defined(_MSC_VER) +#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__GNUC__) +#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message))) +#else +#define GTEST_INTERNAL_DEPRECATED(message) +#endif + +#endif // !defined(GTEST_INTERNAL_DEPRECATED) + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/test/gtest/include/gtest/internal/gtest-string.h b/test/gtest/include/gtest/internal/gtest-string.h index 97f1a7fdd2..82aaa63bf4 100644 --- a/test/gtest/include/gtest/internal/gtest-string.h +++ b/test/gtest/include/gtest/internal/gtest-string.h @@ -27,17 +27,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // -// This header file is #included by . +// This header file is #included by gtest-internal.h. // It should not be #included by other files. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ @@ -94,7 +94,8 @@ class GTEST_API_ String { static const char* Utf16ToAnsi(LPCWSTR utf16_str); #endif - // Compares two C strings. Returns true iff they have the same content. + // Compares two C strings. Returns true if and only if they have the same + // content. // // Unlike strcmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, @@ -107,16 +108,16 @@ class GTEST_API_ String { // returned. static std::string ShowWideCString(const wchar_t* wide_c_str); - // Compares two wide C strings. Returns true iff they have the same - // content. + // Compares two wide C strings. Returns true if and only if they have the + // same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); - // Compares two C strings, ignoring case. Returns true iff they - // have the same content. + // Compares two C strings, ignoring case. Returns true if and only if + // they have the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL C string, @@ -124,8 +125,8 @@ class GTEST_API_ String { static bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs); - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. + // Compares two wide C strings, ignoring case. Returns true if and only if + // they have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, @@ -139,8 +140,8 @@ class GTEST_API_ String { static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); - // Returns true iff the given string ends with the given suffix, ignoring - // case. Any string is considered to end with an empty suffix. + // Returns true if and only if the given string ends with the given suffix, + // ignoring case. Any string is considered to end with an empty suffix. static bool EndsWithCaseInsensitive( const std::string& str, const std::string& suffix); @@ -150,6 +151,9 @@ class GTEST_API_ String { // Formats an int value as "%X". static std::string FormatHexInt(int value); + // Formats an int value as "%X". + static std::string FormatHexUInt32(UInt32 value); + // Formats a byte as "%02X". static std::string FormatByte(unsigned char value); diff --git a/test/gtest/include/gtest/internal/gtest-tuple.h b/test/gtest/include/gtest/internal/gtest-tuple.h index 7b3dfc312d..e9b405340a 100644 --- a/test/gtest/include/gtest/internal/gtest-tuple.h +++ b/test/gtest/include/gtest/internal/gtest-tuple.h @@ -53,6 +53,14 @@ private: #endif +// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict +// with our own definitions. Therefore using our own tuple does not work on +// those compilers. +#if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */ +# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ +GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." +#endif + // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple= 1600 /* 1600 is Visual Studio 2010 */ +# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ +GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." +#endif + $range i 0..n-1 $range j 0..n diff --git a/test/gtest/include/gtest/internal/gtest-type-util.h b/test/gtest/include/gtest/internal/gtest-type-util.h index e46f7cfcb4..3d7542d1fb 100644 --- a/test/gtest/include/gtest/internal/gtest-type-util.h +++ b/test/gtest/include/gtest/internal/gtest-type-util.h @@ -30,17 +30,17 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most 50 types in a list, and at most 50 -// type-parameterized tests in one type-parameterized test case. +// type-parameterized tests in one type-parameterized test suite. // Please contact googletestframework@googlegroups.com if you need // more. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ @@ -57,6 +57,22 @@ namespace testing { namespace internal { +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. @@ -72,10 +88,10 @@ std::string GetTypeName() { # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ - char* const readable_name = __cxa_demangle(name, 0, 0, &status); + char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); - return name_str; + return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC @@ -89,18 +105,6 @@ std::string GetTypeName() { #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P -// AssertyTypeEq::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template -struct AssertTypeEq; - -template -struct AssertTypeEq { - typedef bool type; -}; - // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't @@ -3295,8 +3299,8 @@ struct Templates list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). +// or a Types<...> list in TYPED_TEST_SUITE() and +// INSTANTIATE_TYPED_TEST_SUITE_P(). template struct TypeList { diff --git a/test/gtest/include/gtest/internal/gtest-type-util.h.pump b/test/gtest/include/gtest/internal/gtest-type-util.h.pump index 251fdf025b..5e31b7b320 100644 --- a/test/gtest/include/gtest/internal/gtest-type-util.h.pump +++ b/test/gtest/include/gtest/internal/gtest-type-util.h.pump @@ -28,17 +28,18 @@ $var n = 50 $$ Maximum length of type lists we want to support. // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most $n types in a list, and at most $n -// type-parameterized tests in one type-parameterized test case. +// type-parameterized tests in one type-parameterized test suite. // Please contact googletestframework@googlegroups.com if you need // more. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ @@ -55,6 +56,22 @@ $var n = 50 $$ Maximum length of type lists we want to support. namespace testing { namespace internal { +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. @@ -70,10 +87,10 @@ std::string GetTypeName() { # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ - char* const readable_name = __cxa_demangle(name, 0, 0, &status); + char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); - return name_str; + return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC @@ -87,18 +104,6 @@ std::string GetTypeName() { #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P -// AssertyTypeEq::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template -struct AssertTypeEq; - -template -struct AssertTypeEq { - typedef bool type; -}; - // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't @@ -274,8 +279,8 @@ struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> { ]] // The TypeList template makes it possible to use either a single type -// or a Types<...> list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). +// or a Types<...> list in TYPED_TEST_SUITE() and +// INSTANTIATE_TYPED_TEST_SUITE_P(). template struct TypeList { diff --git a/test/gtest/src/gtest-all.cc b/test/gtest/src/gtest-all.cc index 0a9cee5223..ad292905cf 100644 --- a/test/gtest/src/gtest-all.cc +++ b/test/gtest/src/gtest-all.cc @@ -26,10 +26,9 @@ // 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. + // -// Author: mheule@google.com (Markus Heule) -// -// Google C++ Testing Framework (Google Test) +// Google C++ Testing and Mocking Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. @@ -42,6 +41,7 @@ #include "src/gtest.cc" #include "src/gtest-death-test.cc" #include "src/gtest-filepath.cc" +#include "src/gtest-matchers.cc" #include "src/gtest-port.cc" #include "src/gtest-printers.cc" #include "src/gtest-test-part.cc" diff --git a/test/gtest/src/gtest-death-test.cc b/test/gtest/src/gtest-death-test.cc index a6023fce4f..da09a1cfc2 100644 --- a/test/gtest/src/gtest-death-test.cc +++ b/test/gtest/src/gtest-death-test.cc @@ -26,13 +26,16 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) + // // This file implements death tests. #include "gtest/gtest-death-test.h" + +#include + #include "gtest/internal/gtest-port.h" +#include "gtest/internal/custom/gtest.h" #if GTEST_HAS_DEATH_TEST @@ -61,26 +64,36 @@ # include # endif // GTEST_OS_QNX +# if GTEST_OS_FUCHSIA +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# endif // GTEST_OS_FUCHSIA + #endif // GTEST_HAS_DEATH_TEST #include "gtest/gtest-message.h" #include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. -static const char kDefaultDeathTestStyle[] = "fast"; +// +// This is defined in internal/gtest-port.h as "fast", but can be overridden by +// a definition in internal/custom/gtest-port.h. The recommended value, which is +// used internally at Google, is "threadsafe". +static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE; GTEST_DEFINE_string_( death_test_style, @@ -109,8 +122,8 @@ GTEST_DEFINE_string_( "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " - "the '|' characters. This flag is specified if and only if the current " - "process is a sub-process launched for running a thread-safe " + "the '|' characters. This flag is specified if and only if the " + "current process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal @@ -120,7 +133,9 @@ namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA static bool g_in_fast_death_test_child = false; +# endif // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as @@ -128,10 +143,10 @@ static bool g_in_fast_death_test_child = false; // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA - // On Windows, death tests are thread-safe regardless of the value of the - // death_test_style flag. + // On Windows and Fuchsia, death tests are thread-safe regardless of the value + // of the death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else @@ -151,7 +166,7 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return exit_status == exit_code_; @@ -159,19 +174,27 @@ bool ExitedWithCode::operator()(int exit_status) const { return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { +# if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) + { + bool result; + if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { + return result; + } + } +# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA namespace internal { @@ -182,7 +205,7 @@ namespace internal { static std::string ExitSummary(int exit_code) { Message m; -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA m << "Exited with exit status " << exit_code; @@ -198,7 +221,7 @@ static std::string ExitSummary(int exit_code) { m << " (core dumped)"; } # endif -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return m.GetString(); } @@ -209,7 +232,7 @@ bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the @@ -218,13 +241,19 @@ static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; - if (thread_count == 0) + if (thread_count == 0) { msg << "couldn't detect the number of threads."; - else + } else { msg << "detected " << thread_count << " threads."; + } + msg << " See " + "https://github.com/google/googletest/blob/master/googletest/docs/" + "advanced.md#death-tests-and-threads" + << " for more explanation and suggested solutions, especially if" + << " this is the last message you see before your test times out."; return msg.GetString(); } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; @@ -232,6 +261,13 @@ static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; +#if GTEST_OS_FUCHSIA + +// File descriptor used for the pipe in the child process. +static const int kFuchsiaReadPipeFd = 3; + +#endif + // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; @@ -239,8 +275,6 @@ static const char kDeathTestInternalError = 'I'; // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. -// TODO(vladl@google.com): Unify names and possibly values for -// AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an @@ -248,13 +282,13 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. -void DeathTestAbort(const std::string& message) { +static void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); - if (flag != NULL) { + if (flag != nullptr) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); @@ -334,7 +368,7 @@ static void FailFromInternalError(int fd) { // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); - if (info == NULL) { + if (info == nullptr) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } @@ -342,10 +376,11 @@ DeathTest::DeathTest() { // Creates and returns a death test by dispatching to the current // death test factory. -bool DeathTest::Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) { +bool DeathTest::Create(const char* statement, + Matcher matcher, const char* file, + int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( - statement, regex, file, line, test); + statement, std::move(matcher), file, line, test); } const char* DeathTest::LastMessage() { @@ -361,9 +396,9 @@ std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: - DeathTestImpl(const char* a_statement, const RE* a_regex) + DeathTestImpl(const char* a_statement, Matcher matcher) : statement_(a_statement), - regex_(a_regex), + matcher_(std::move(matcher)), spawned_(false), status_(-1), outcome_(IN_PROGRESS), @@ -371,13 +406,12 @@ class DeathTestImpl : public DeathTest { write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. - ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } - void Abort(AbortReason reason); - virtual bool Passed(bool status_ok); + void Abort(AbortReason reason) override; + bool Passed(bool status_ok) override; const char* statement() const { return statement_; } - const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } @@ -395,13 +429,15 @@ class DeathTestImpl : public DeathTest { // case of unexpected codes. void ReadAndInterpretStatusByte(); + // Returns stderr output from the child process. + virtual std::string GetErrorLogs(); + private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; - // The regular expression which test output must match. DeathTestImpl - // doesn't own this object and should not attempt to delete it. - const RE* const regex_; + // A matcher that's expected to match the stderr output by the child process. + Matcher matcher_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. @@ -463,6 +499,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { set_read_fd(-1); } +std::string DeathTestImpl::GetErrorLogs() { + return GetCapturedStderr(); +} + // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then @@ -516,22 +556,21 @@ static ::std::string FormatDeathTestOutput(const ::std::string& output) { // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. -// regex: A regular expression object to be applied to -// the test's captured standard error output; the death test -// fails if it does not match. +// matcher_: A matcher that's expected to match the stderr output by the child +// process. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // -// Returns true iff all of the above conditions are met. Otherwise, the -// first failing condition, in the order given above, is the one that is +// Returns true if and only if all of the above conditions are met. Otherwise, +// the first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; - const std::string error_message = GetCapturedStderr(); + const std::string error_message = GetErrorLogs(); bool success = false; Message buffer; @@ -552,13 +591,15 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case DIED: if (status_ok) { - const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); - if (matched) { + if (matcher_.Matches(error_message)) { success = true; } else { + std::ostringstream stream; + matcher_.DescribeTo(&stream); buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex()->pattern() << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); + << " Expected: " << stream.str() << "\n" + << "Actual msg:\n" + << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" @@ -607,11 +648,11 @@ bool DeathTestImpl::Passed(bool status_ok) { // class WindowsDeathTest : public DeathTestImpl { public: - WindowsDeathTest(const char* a_statement, - const RE* a_regex, - const char* file, - int line) - : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + WindowsDeathTest(const char* a_statement, Matcher matcher, + const char* file, int line) + : DeathTestImpl(a_statement, std::move(matcher)), + file_(file), + line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); @@ -688,7 +729,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); @@ -697,8 +738,8 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. - SECURITY_ATTRIBUTES handles_are_inheritable = { - sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES), + nullptr, TRUE}; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, @@ -709,13 +750,13 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, - TRUE, // The event will automatically reset to non-signaled state. - FALSE, // The initial state is non-signalled. - NULL)); // The even is unnamed. - GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + - info->test_case_name() + "." + info->name(); + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + nullptr)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + @@ -728,10 +769,9 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT - GTEST_DEATH_TEST_CHECK_( - _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, - executable_path, - _MAX_PATH)); + GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr, + executable_path, + _MAX_PATH)); std::string command_line = std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + @@ -752,33 +792,290 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; - GTEST_DEATH_TEST_CHECK_(::CreateProcessA( - executable_path, - const_cast(command_line.c_str()), - NULL, // Retuned process handle is not inheritable. - NULL, // Retuned thread handle is not inheritable. - TRUE, // Child inherits all inheritable handles (for write_handle_). - 0x0, // Default creation flags. - NULL, // Inherit the parent's environment. - UnitTest::GetInstance()->original_working_dir(), - &startup_info, - &process_info) != FALSE); + GTEST_DEATH_TEST_CHECK_( + ::CreateProcessA( + executable_path, const_cast(command_line.c_str()), + nullptr, // Retuned process handle is not inheritable. + nullptr, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + nullptr, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), &startup_info, + &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } -# else // We are not on Windows. + +# elif GTEST_OS_FUCHSIA + +class FuchsiaDeathTest : public DeathTestImpl { + public: + FuchsiaDeathTest(const char* a_statement, Matcher matcher, + const char* file, int line) + : DeathTestImpl(a_statement, std::move(matcher)), + file_(file), + line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + int Wait() override; + TestRole AssumeRole() override; + std::string GetErrorLogs() override; + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // The stderr data captured by the child process. + std::string captured_stderr_; + + zx::process child_process_; + zx::channel exception_channel_; + zx::socket stderr_socket_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { args_.push_back(nullptr); } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + int size() { + return args_.size() - 1; + } + + private: + std::vector args_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int FuchsiaDeathTest::Wait() { + const int kProcessKey = 0; + const int kSocketKey = 1; + const int kExceptionKey = 2; + + if (!spawned()) + return 0; + + // Create a port to wait for socket/task/exception events. + zx_status_t status_zx; + zx::port port; + status_zx = zx::port::create(0, &port); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Register to wait for the child process to terminate. + status_zx = child_process_.wait_async( + port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Register to wait for the socket to be readable or closed. + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Register to wait for an exception. + status_zx = exception_channel_.wait_async( + port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + bool process_terminated = false; + bool socket_closed = false; + do { + zx_port_packet_t packet = {}; + status_zx = port.wait(zx::time::infinite(), &packet); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + if (packet.key == kExceptionKey) { + // Process encountered an exception. Kill it directly rather than + // letting other handlers process the event. We will get a kProcessKey + // event when the process actually terminates. + status_zx = child_process_.kill(); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } else if (packet.key == kProcessKey) { + // Process terminated. + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); + process_terminated = true; + } else if (packet.key == kSocketKey) { + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + if (packet.signal.observed & ZX_SOCKET_READABLE) { + // Read data from the socket. + constexpr size_t kBufferSize = 1024; + do { + size_t old_length = captured_stderr_.length(); + size_t bytes_read = 0; + captured_stderr_.resize(old_length + kBufferSize); + status_zx = stderr_socket_.read( + 0, &captured_stderr_.front() + old_length, kBufferSize, + &bytes_read); + captured_stderr_.resize(old_length + bytes_read); + } while (status_zx == ZX_OK); + if (status_zx == ZX_ERR_PEER_CLOSED) { + socket_closed = true; + } else { + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } + } else { + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED); + socket_closed = true; + } + } + } while (!process_terminated && !socket_closed); + + ReadAndInterpretStatusByte(); + + zx_info_process_t buffer; + status_zx = child_process_.get_info( + ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + GTEST_DEATH_TEST_CHECK_(buffer.exited); + set_status(buffer.return_code); + return status(); +} + +// The AssumeRole process for a Fuchsia death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != nullptr) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(kFuchsiaReadPipeFd); + return EXECUTE_TEST; + } + + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // Build the child process command line. + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + + StreamableToString(line_) + "|" + + StreamableToString(death_test_index); + Arguments args; + args.AddArguments(GetInjectableArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + // Build the pipe for communication with the child. + zx_status_t status; + zx_handle_t child_pipe_handle; + int child_pipe_fd; + status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + set_read_fd(child_pipe_fd); + + // Set the pipe handle for the child. + fdio_spawn_action_t spawn_actions[2] = {}; + fdio_spawn_action_t* add_handle_action = &spawn_actions[0]; + add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; + add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd); + add_handle_action->h.handle = child_pipe_handle; + + // Create a socket pair will be used to receive the child process' stderr. + zx::socket stderr_producer_socket; + status = + zx::socket::create(0, &stderr_producer_socket, &stderr_socket_); + GTEST_DEATH_TEST_CHECK_(status >= 0); + int stderr_producer_fd = -1; + status = + fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd); + GTEST_DEATH_TEST_CHECK_(status >= 0); + + // Make the stderr socket nonblocking. + GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0); + + fdio_spawn_action_t* add_stderr_action = &spawn_actions[1]; + add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD; + add_stderr_action->fd.local_fd = stderr_producer_fd; + add_stderr_action->fd.target_fd = STDERR_FILENO; + + // Create a child job. + zx_handle_t child_job = ZX_HANDLE_INVALID; + status = zx_job_create(zx_job_default(), 0, & child_job); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + zx_policy_basic_t policy; + policy.condition = ZX_POL_NEW_ANY; + policy.policy = ZX_POL_ACTION_ALLOW; + status = zx_job_set_policy( + child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Create an exception channel attached to the |child_job|, to allow + // us to suppress the system default exception handler from firing. + status = + zx_task_create_exception_channel( + child_job, 0, exception_channel_.reset_and_get_address()); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Spawn the child process. + status = fdio_spawn_etc( + child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), nullptr, + 2, spawn_actions, child_process_.reset_and_get_address(), nullptr); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + set_spawned(true); + return OVERSEE_TEST; +} + +std::string FuchsiaDeathTest::GetErrorLogs() { + return captured_stderr_; +} + +#else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. class ForkingDeathTest : public DeathTestImpl { public: - ForkingDeathTest(const char* statement, const RE* regex); + ForkingDeathTest(const char* statement, Matcher matcher); // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); + int Wait() override; protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } @@ -789,9 +1086,9 @@ class ForkingDeathTest : public DeathTestImpl { }; // Constructs a ForkingDeathTest. -ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) - : DeathTestImpl(a_statement, a_regex), - child_pid_(-1) {} +ForkingDeathTest::ForkingDeathTest(const char* a_statement, + Matcher matcher) + : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the @@ -812,9 +1109,9 @@ int ForkingDeathTest::Wait() { // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: - NoExecDeathTest(const char* a_statement, const RE* a_regex) : - ForkingDeathTest(a_statement, a_regex) { } - virtual TestRole AssumeRole(); + NoExecDeathTest(const char* a_statement, Matcher matcher) + : ForkingDeathTest(a_statement, std::move(matcher)) {} + TestRole AssumeRole() override; }; // The AssumeRole process for a fork-and-run death test. It implements a @@ -867,14 +1164,21 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: - ExecDeathTest(const char* a_statement, const RE* a_regex, - const char* file, int line) : - ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } - virtual TestRole AssumeRole(); + ExecDeathTest(const char* a_statement, Matcher matcher, + const char* file, int line) + : ForkingDeathTest(a_statement, std::move(matcher)), + file_(file), + line_(line) {} + TestRole AssumeRole() override; + private: - static ::std::vector - GetArgvsForDeathTestChildProcess() { - ::std::vector args = GetInjectableArgvs(); + static ::std::vector GetArgvsForDeathTestChildProcess() { + ::std::vector args = GetInjectableArgvs(); +# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) + ::std::vector extra_args = + GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); + args.insert(args.end(), extra_args.begin(), extra_args.end()); +# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) return args; } // The name of the file in which the death test is located. @@ -886,9 +1190,7 @@ class ExecDeathTest : public ForkingDeathTest { // Utility class for accumulating command-line arguments. class Arguments { public: - Arguments() { - args_.push_back(NULL); - } + Arguments() { args_.push_back(nullptr); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); @@ -970,6 +1272,7 @@ static int ExecDeathTestChildMain(void* child_arg) { } # endif // !GTEST_OS_QNX +# if GTEST_HAS_CLONE // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive @@ -979,18 +1282,26 @@ static int ExecDeathTestChildMain(void* child_arg) { // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. -void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; -void StackLowerThanAddress(const void* ptr, bool* result) { +static void StackLowerThanAddress(const void* ptr, + bool* result) GTEST_NO_INLINE_; +// HWAddressSanitizer add a random tag to the MSB of the local variable address, +// making comparison result unpredictable. +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +static void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } -bool StackGrowsDown() { +// Make sure AddressSanitizer does not tamper with the stack here. +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +static bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } +# endif // GTEST_HAS_CLONE // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The @@ -1028,7 +1339,8 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. - child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); + child_pid = + spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); @@ -1052,9 +1364,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); - const size_t stack_size = getpagesize(); + const auto stack_size = static_cast(getpagesize()); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. - void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); @@ -1068,8 +1380,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); - GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && - reinterpret_cast(stack_top) % kMaxStackAlignment == 0); + GTEST_DEATH_TEST_CHECK_( + static_cast(stack_size) > kMaxStackAlignment && + reinterpret_cast(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); @@ -1086,7 +1399,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { # endif // GTEST_OS_QNX # if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( - sigaction(SIGPROF, &saved_sigprof_action, NULL)); + sigaction(SIGPROF, &saved_sigprof_action, nullptr)); # endif // GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_(child_pid != -1); @@ -1104,7 +1417,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } @@ -1115,9 +1428,9 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" - + info->test_case_name() + "." + info->name(); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" @@ -1150,7 +1463,8 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. -bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, +bool DefaultDeathTestFactory::Create(const char* statement, + Matcher matcher, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); @@ -1159,7 +1473,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, const int death_test_index = impl->current_test_info() ->increment_death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message( "Death test count (" + StreamableToString(death_test_index) @@ -1170,7 +1484,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { - *test = NULL; + *test = nullptr; return true; } } @@ -1179,15 +1493,22 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { - *test = new WindowsDeathTest(statement, regex, file, line); + *test = new WindowsDeathTest(statement, std::move(matcher), file, line); + } + +# elif GTEST_OS_FUCHSIA + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line); } # else if (GTEST_FLAG(death_test_style) == "threadsafe") { - *test = new ExecDeathTest(statement, regex, file, line); + *test = new ExecDeathTest(statement, std::move(matcher), file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { - *test = new NoExecDeathTest(statement, regex); + *test = new NoExecDeathTest(statement, std::move(matcher)); } # endif // GTEST_OS_WINDOWS @@ -1202,31 +1523,11 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, return true; } -// Splits a given string on a given delimiter, populating a given -// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have -// ::std::string, so we can use it here. -static void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest) { - ::std::vector< ::std::string> parsed; - ::std::string::size_type pos = 0; - while (::testing::internal::AlwaysTrue()) { - const ::std::string::size_type colon = str.find(delimiter, pos); - if (colon == ::std::string::npos) { - parsed.push_back(str.substr(pos)); - break; - } else { - parsed.push_back(str.substr(pos, colon - pos)); - pos = colon + 1; - } - } - dest->swap(parsed); -} - # if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. -int GetStatusFileDescriptor(unsigned int parent_process_id, +static int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, @@ -1237,15 +1538,13 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, StreamableToString(parent_process_id)); } - // TODO(vladl@google.com): Replace the following check with a - // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; - // The newly initialized handle is accessible only in in the parent + // The newly initialized handle is accessible only in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, @@ -1294,7 +1593,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { - if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + if (GTEST_FLAG(internal_run_death_test) == "") return nullptr; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. @@ -1322,6 +1621,16 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); + +# elif GTEST_OS_FUCHSIA + + if (fields.size() != 3 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + # else if (fields.size() != 4 diff --git a/test/gtest/src/gtest-filepath.cc b/test/gtest/src/gtest-filepath.cc index 6be58b6fca..bd7b99ff03 100644 --- a/test/gtest/src/gtest-filepath.cc +++ b/test/gtest/src/gtest-filepath.cc @@ -26,28 +26,25 @@ // 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. -// -// Authors: keith.ray@gmail.com (Keith Ray) -#include "gtest/gtest-message.h" #include "gtest/internal/gtest-filepath.h" -#include "gtest/internal/gtest-port.h" #include +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-message.h" #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include # include -#elif GTEST_OS_SYMBIAN -// Symbian OpenC has PATH_MAX in sys/syslimits.h -# include #else # include # include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE +#include "gtest/internal/gtest-string.h" + #if GTEST_OS_WINDOWS # define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) @@ -58,8 +55,6 @@ # define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS -#include "gtest/internal/gtest-string.h" - namespace testing { namespace internal { @@ -70,7 +65,6 @@ namespace internal { // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; -const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use @@ -84,7 +78,6 @@ const char kCurrentDirectoryString[] = ".\\"; # endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; -const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS @@ -99,16 +92,24 @@ static bool IsPathSeparator(char c) { // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE - // Windows CE doesn't have a current directory, so we just return +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || ARDUINO || defined(ESP_PLATFORM) + // These platforms do not have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); + return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); + char* result = getcwd(cwd, sizeof(cwd)); +# if GTEST_OS_NACL + // getcwd will likely fail in NaCl due to the sandbox, so return something + // reasonable. The user may have provided a shim implementation for getcwd, + // however, so fallback only when failure is detected. + return FilePath(result == nullptr ? kCurrentDirectoryString : cwd); +# endif // GTEST_OS_NACL + return FilePath(result == nullptr ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } @@ -125,7 +126,7 @@ FilePath FilePath::RemoveExtension(const char* extension) const { return *this; } -// Returns a pointer to the last occurence of a valid path separator in +// Returns a pointer to the last occurrence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { @@ -133,8 +134,8 @@ const char* FilePath::FindLastPathSeparator() const { #if GTEST_HAS_ALT_PATH_SEP_ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); // Comparing two pointers of which only one is NULL is undefined. - if (last_alt_sep != NULL && - (last_sep == NULL || last_alt_sep > last_sep)) { + if (last_alt_sep != nullptr && + (last_sep == nullptr || last_alt_sep > last_sep)) { return last_alt_sep; } #endif @@ -162,7 +163,7 @@ FilePath FilePath::RemoveFileName() const { const char* const last_sep = FindLastPathSeparator(); std::string dir; if (last_sep) { - dir = std::string(c_str(), last_sep + 1 - c_str()); + dir = std::string(c_str(), static_cast(last_sep + 1 - c_str())); } else { dir = kCurrentDirectoryString; } @@ -247,9 +248,6 @@ bool FilePath::DirectoryExists() const { // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS - // TODO(wan@google.com): on Windows a network share like - // \\server\share can be a root directory, although it cannot be the - // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); @@ -321,7 +319,7 @@ bool FilePath::CreateFolder() const { #if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); - int result = CreateDirectory(unicode, NULL) ? 0 : -1; + int result = CreateDirectory(unicode, nullptr) ? 0 : -1; delete [] unicode; #elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); @@ -347,9 +345,8 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". -// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { - if (pathname_.c_str() == NULL) { + if (pathname_.c_str() == nullptr) { pathname_ = ""; return; } diff --git a/test/gtest/src/gtest-internal-inl.h b/test/gtest/src/gtest-internal-inl.h index 35df303cca..8ed70daab0 100644 --- a/test/gtest/src/gtest-internal-inl.h +++ b/test/gtest/src/gtest-internal-inl.h @@ -27,24 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Utility functions and classes used by the Google C++ testing framework. -// -// Author: wan@google.com (Zhanyong Wan) -// +// Utility functions and classes used by the Google C++ testing framework.// // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ -// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is -// part of Google Test's implementation; otherwise it's undefined. -#if !GTEST_IMPLEMENTATION_ -// A user is trying to include this from his code - just say no. -# error "gtest-internal-inl.h is part of Google Test's internal implementation." -# error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION_ - #ifndef _WIN32_WCE # include #endif // !_WIN32_WCE @@ -53,6 +42,7 @@ #include // For memmove. #include +#include #include #include @@ -67,9 +57,12 @@ # include // NOLINT #endif // GTEST_OS_WINDOWS -#include "gtest/gtest.h" // NOLINT +#include "gtest/gtest.h" #include "gtest/gtest-spi.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // Declares the flags. @@ -94,24 +87,26 @@ const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; +const char kPrintUTF8Flag[] = "print_utf8"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; +const char kFlagfileFlag[] = "flagfile"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); -// Returns true iff Google Test should use colors in the output. +// Returns true if and only if Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. @@ -173,6 +168,7 @@ class GTestFlagSaver { list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); + print_utf8_ = GTEST_FLAG(print_utf8); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); @@ -194,6 +190,7 @@ class GTestFlagSaver { GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(print_utf8) = print_utf8_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; @@ -215,6 +212,7 @@ class GTestFlagSaver { bool list_tests_; std::string output_; bool print_time_; + bool print_utf8_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; @@ -233,7 +231,7 @@ GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number @@ -268,8 +266,8 @@ GTEST_API_ bool ShouldShard(const char* total_shards_str, GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); @@ -300,7 +298,8 @@ void ForEach(const Container& c, Functor functor) { // in range [0, v.size()). template inline E GetElementOr(const std::vector& v, int i, E default_value) { - return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; + return (i < 0 || i >= static_cast(v.size())) ? default_value + : v[static_cast(i)]; } // Performs an in-place shuffle of a range of the vector's elements. @@ -322,8 +321,11 @@ void ShuffleRange(internal::Random* random, int begin, int end, // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; - const int selected = begin + random->Generate(range_width); - std::swap((*v)[selected], (*v)[last_in_range]); + const int selected = + begin + + static_cast(random->Generate(static_cast(range_width))); + std::swap((*v)[static_cast(selected)], + (*v)[static_cast(last_in_range)]); } } @@ -350,7 +352,7 @@ class TestPropertyKeyIs { // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} - // Returns true iff the test name of test property matches on key_. + // Returns true if and only if the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return test_property.key() == key_; } @@ -383,17 +385,17 @@ class GTEST_API_ UnitTestOptions { // Functions for processing the gtest_filter flag. - // Returns true iff the wildcard pattern matches the string. The - // first ':' or '\0' character in pattern marks the end of it. + // Returns true if and only if the wildcard pattern matches the string. + // The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); - // Returns true iff the user-specified filter matches the test case - // name and the test name. - static bool FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name); + // Returns true if and only if the user-specified filter matches the test + // suite name and the test name. + static bool FilterMatchesTest(const std::string& test_suite_name, + const std::string& test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. @@ -425,13 +427,17 @@ class OsStackTraceGetterInterface { // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. - virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; + virtual std::string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; @@ -439,25 +445,21 @@ class OsStackTraceGetterInterface { // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: - OsStackTraceGetter() : caller_frame_(NULL) {} - - virtual string CurrentStackTrace(int max_depth, int skip_count) - GTEST_LOCK_EXCLUDED_(mutex_); + OsStackTraceGetter() {} - virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); - - // This string is inserted in place of stack frames that are part of - // Google Test's implementation. - static const char* const kElidedFramesMarker; + std::string CurrentStackTrace(int max_depth, int skip_count) override; + void UponLeavingGTest() override; private: - Mutex mutex_; // protects all internal state +#if GTEST_HAS_ABSL + Mutex mutex_; // Protects all internal state. // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() - // and any calls to CurrentStackTrace() from within the user code. - void* caller_frame_; + // and any calls to the stack trace code from within the user code. + void* caller_frame_ = nullptr; +#endif // GTEST_HAS_ABSL GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; @@ -477,7 +479,7 @@ class DefaultGlobalTestPartResultReporter explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult& result) override; private: UnitTestImpl* const unit_test_; @@ -493,7 +495,7 @@ class DefaultPerThreadTestPartResultReporter explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult& result) override; private: UnitTestImpl* const unit_test_; @@ -531,22 +533,25 @@ class GTEST_API_ UnitTestImpl { void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); - // Gets the number of successful test cases. - int successful_test_case_count() const; + // Gets the number of successful test suites. + int successful_test_suite_count() const; - // Gets the number of failed test cases. - int failed_test_case_count() const; + // Gets the number of failed test suites. + int failed_test_suite_count() const; - // Gets the number of all test cases. - int total_test_case_count() const; + // Gets the number of all test suites. + int total_test_suite_count() const; - // Gets the number of all test cases that contain at least one test + // Gets the number of all test suites that contain at least one test // that should run. - int test_case_to_run_count() const; + int test_suite_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; + // Gets the number of skipped tests. + int skipped_test_count() const; + // Gets the number of failed tests. int failed_test_count() const; @@ -572,27 +577,33 @@ class GTEST_API_ UnitTestImpl { // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } - // Returns true iff the unit test passed (i.e. all test cases passed). + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). bool Passed() const { return !Failed(); } - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). bool Failed() const { - return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed(); } - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[i]; + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite* GetTestSuite(int i) const { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast(i)]; } - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i) { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[index]; + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* GetTestCase(int i) const { return GetTestSuite(i); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite* GetMutableSuiteCase(int i) { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast(index)]; } // Provides access to the event listener list. @@ -629,30 +640,38 @@ class GTEST_API_ UnitTestImpl { // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; - // Finds and returns a TestCase with the given name. If one doesn't + // Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // - // test_case_name: name of the test case + // test_suite_name: name of the test suite // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase* GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + TestCase* GetTestCase(const char* test_case_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + return GetTestSuite(test_case_name, type_param, set_up_tc, tear_down_tc); + } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Adds a TestInfo to the unit test. // // Arguments: // - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite // test_info: the TestInfo object - void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, + void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, TestInfo* test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program @@ -667,23 +686,20 @@ class GTEST_API_ UnitTestImpl { << "Failed to get the current working directory."; } - GetTestCase(test_info->test_case_name(), - test_info->type_param(), - set_up_tc, - tear_down_tc)->AddTestInfo(test_info); + GetTestSuite(test_info->test_suite_name(), test_info->type_param(), + set_up_tc, tear_down_tc) + ->AddTestInfo(test_info); } -#if GTEST_HAS_PARAM_TEST - // Returns ParameterizedTestCaseRegistry object used to keep track of + // Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() { return parameterized_test_registry_; } -#endif // GTEST_HAS_PARAM_TEST - // Sets the TestCase object for the test that's currently running. - void set_current_test_case(TestCase* a_current_test_case) { - current_test_case_ = a_current_test_case; + // Sets the TestSuite object for the test that's currently running. + void set_current_test_suite(TestSuite* a_current_test_suite) { + current_test_suite_ = a_current_test_suite; } // Sets the TestInfo object for the test that's currently running. If @@ -694,7 +710,7 @@ class GTEST_API_ UnitTestImpl { } // Registers all parameterized tests defined using TEST_P and - // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // INSTANTIATE_TEST_SUITE_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has guards // protecting from registering the tests more then once. If // value-parameterized tests are disabled, RegisterParameterizedTests is @@ -709,7 +725,7 @@ class GTEST_API_ UnitTestImpl { // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { - ForEach(test_cases_, TestCase::ClearTestCaseResult); + ForEach(test_suites_, TestSuite::ClearTestSuiteResult); } // Clears the results of ad-hoc test assertions. @@ -718,7 +734,7 @@ class GTEST_API_ UnitTestImpl { } // Adds a TestProperty to the current TestResult object when invoked in a - // context of a test or a test case, or to the global property set. If the + // context of a test or a test suite, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. void RecordProperty(const TestProperty& test_property); @@ -730,7 +746,7 @@ class GTEST_API_ UnitTestImpl { // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the - // result in each TestCase and TestInfo object. + // result in each TestSuite and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. @@ -739,7 +755,7 @@ class GTEST_API_ UnitTestImpl { // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); - const TestCase* current_test_case() const { return current_test_case_; } + const TestSuite* current_test_suite() const { return current_test_suite_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } @@ -800,11 +816,11 @@ class GTEST_API_ UnitTestImpl { // Gets the random number generator. internal::Random* random() { return &random_; } - // Shuffles all test cases, and the tests within each test case, + // Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void ShuffleTests(); - // Restores the test cases and tests to their order before the first shuffle. + // Restores the test suites and tests to their order before the first shuffle. void UnshuffleTests(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment @@ -844,33 +860,31 @@ class GTEST_API_ UnitTestImpl { // before/after the tests are run. std::vector environments_; - // The vector of TestCases in their original order. It owns the + // The vector of TestSuites in their original order. It owns the // elements in the vector. - std::vector test_cases_; + std::vector test_suites_; - // Provides a level of indirection for the test case list to allow - // easy shuffling and restoring the test case order. The i-th - // element of this vector is the index of the i-th test case in the + // Provides a level of indirection for the test suite list to allow + // easy shuffling and restoring the test suite order. The i-th + // element of this vector is the index of the i-th test suite in the // shuffled order. - std::vector test_case_indices_; + std::vector test_suite_indices_; -#if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. - internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + internal::ParameterizedTestSuiteRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; -#endif // GTEST_HAS_PARAM_TEST - // Index of the last death test case registered. Initially -1. - int last_death_test_case_; + // Index of the last death test suite registered. Initially -1. + int last_death_test_suite_; - // This points to the TestCase for the currently running test. It - // changes as Google Test goes through one test case after another. + // This points to the TestSuite for the currently running test. It + // changes as Google Test goes through one test suite after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. - TestCase* current_test_case_; + TestSuite* current_test_suite_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When @@ -898,7 +912,7 @@ class GTEST_API_ UnitTestImpl { // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; - // True iff PostFlagParsingInit() has been called. + // True if and only if PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. @@ -917,8 +931,8 @@ class GTEST_API_ UnitTestImpl { #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. - internal::scoped_ptr internal_run_death_test_flag_; - internal::scoped_ptr death_test_factory_; + std::unique_ptr internal_run_death_test_flag_; + std::unique_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. @@ -968,32 +982,6 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // platform. GTEST_API_ std::string GetLastErrnoDescription(); -# if GTEST_OS_WINDOWS -// Provides leak-safe Windows kernel handle ownership. -class AutoHandle { - public: - AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} - explicit AutoHandle(HANDLE handle) : handle_(handle) {} - - ~AutoHandle() { Reset(); } - - HANDLE Get() const { return handle_; } - void Reset() { Reset(INVALID_HANDLE_VALUE); } - void Reset(HANDLE handle) { - if (handle != handle_) { - if (handle_ != INVALID_HANDLE_VALUE) - ::CloseHandle(handle_); - handle_ = handle; - } - } - - private: - HANDLE handle_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); -}; -# endif // GTEST_OS_WINDOWS - // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use @@ -1027,8 +1015,6 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { const bool parse_success = *end == '\0' && errno == 0; - // TODO(vladl@google.com): Convert this to compile time assertion when it is - // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); @@ -1075,37 +1061,35 @@ class StreamingListener : public EmptyTestEventListener { virtual ~AbstractSocketWriter() {} // Sends a string to the socket. - virtual void Send(const string& message) = 0; + virtual void Send(const std::string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. - void SendLn(const string& message) { - Send(message + "\n"); - } + void SendLn(const std::string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: - SocketWriter(const string& host, const string& port) + SocketWriter(const std::string& host, const std::string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } - virtual ~SocketWriter() { + ~SocketWriter() override { if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. - virtual void Send(const string& message) { + void Send(const std::string& message) override { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; - const int len = static_cast(message.length()); - if (write(sockfd_, message.c_str(), len) != len) { + const auto len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != static_cast(len)) { GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " << host_name_ << ":" << port_num_; @@ -1117,7 +1101,7 @@ class StreamingListener : public EmptyTestEventListener { void MakeConnection(); // Closes the socket. - void CloseConnection() { + void CloseConnection() override { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; @@ -1126,26 +1110,28 @@ class StreamingListener : public EmptyTestEventListener { } int sockfd_; // socket file descriptor - const string host_name_; - const string port_num_; + const std::string host_name_; + const std::string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static string UrlEncode(const char* str); + static std::string UrlEncode(const char* str); - StreamingListener(const string& host, const string& port) - : socket_writer_(new SocketWriter(host, port)) { Start(); } + StreamingListener(const std::string& host, const std::string& port) + : socket_writer_(new SocketWriter(host, port)) { + Start(); + } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } - void OnTestProgramStart(const UnitTest& /* unit_test */) { + void OnTestProgramStart(const UnitTest& /* unit_test */) override { SendLn("event=TestProgramStart"); } - void OnTestProgramEnd(const UnitTest& unit_test) { + void OnTestProgramEnd(const UnitTest& unit_test) override { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); @@ -1154,42 +1140,47 @@ class StreamingListener : public EmptyTestEventListener { socket_writer_->CloseConnection(); } - void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + void OnTestIterationStart(const UnitTest& /* unit_test */, + int iteration) override { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } - void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + void OnTestIterationEnd(const UnitTest& unit_test, + int /* iteration */) override { SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + "ms"); } - void OnTestCaseStart(const TestCase& test_case) { + // Note that "event=TestCaseStart" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseStart(const TestCase& test_case) override { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } - void OnTestCaseEnd(const TestCase& test_case) { - SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) - + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) - + "ms"); + // Note that "event=TestCaseEnd" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseEnd(const TestCase& test_case) override { + SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + + "ms"); } - void OnTestStart(const TestInfo& test_info) { + void OnTestStart(const TestInfo& test_info) override { SendLn(std::string("event=TestStart&name=") + test_info.name()); } - void OnTestEnd(const TestInfo& test_info) { + void OnTestEnd(const TestInfo& test_info) override { SendLn("event=TestEnd&passed=" + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } - void OnTestPartResult(const TestPartResult& test_part_result) { + void OnTestPartResult(const TestPartResult& test_part_result) override { const char* file_name = test_part_result.file_name(); - if (file_name == NULL) - file_name = ""; + if (file_name == nullptr) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); @@ -1197,15 +1188,15 @@ class StreamingListener : public EmptyTestEventListener { private: // Sends the given message and a newline to the socket. - void SendLn(const string& message) { socket_writer_->SendLn(message); } + void SendLn(const std::string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } - string FormatBool(bool value) { return value ? "1" : "0"; } + std::string FormatBool(bool value) { return value ? "1" : "0"; } - const scoped_ptr socket_writer_; + const std::unique_ptr socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener @@ -1215,4 +1206,6 @@ class StreamingListener : public EmptyTestEventListener { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/test/gtest/src/gtest-matchers.cc b/test/gtest/src/gtest-matchers.cc new file mode 100644 index 0000000000..7d2fb6851e --- /dev/null +++ b/test/gtest/src/gtest-matchers.cc @@ -0,0 +1,97 @@ +// Copyright 2007, Google Inc. +// 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 Google Inc. 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 +// OWNER OR CONTRIBUTORS 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. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-matchers.h" + +#include + +namespace testing { + +// Constructs a matcher that matches a const std::string& whose value is +// equal to s. +Matcher::Matcher(const std::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a const std::string& whose value is +// equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a std::string whose value is equal to +// s. +Matcher::Matcher(const std::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a std::string whose value is equal to +// s. +Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } + +#if GTEST_HAS_ABSL +// Constructs a matcher that matches a const absl::string_view& whose value is +// equal to s. +Matcher::Matcher(const std::string& s) { + *this = Eq(s); +} + +// Constructs a matcher that matches a const absl::string_view& whose value is +// equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a const absl::string_view& whose value is +// equal to s. +Matcher::Matcher(absl::string_view s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a absl::string_view whose value is equal to +// s. +Matcher::Matcher(const std::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a absl::string_view whose value is equal to +// s. +Matcher::Matcher(const char* s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a absl::string_view whose value is equal to +// s. +Matcher::Matcher(absl::string_view s) { + *this = Eq(std::string(s)); +} +#endif // GTEST_HAS_ABSL + +} // namespace testing diff --git a/test/gtest/src/gtest-port.cc b/test/gtest/src/gtest-port.cc index 0c4df5f29a..fc5ba6becc 100644 --- a/test/gtest/src/gtest-port.cc +++ b/test/gtest/src/gtest-port.cc @@ -26,24 +26,28 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + #include "gtest/internal/gtest-port.h" #include -#include #include +#include #include +#include +#include -#if GTEST_OS_WINDOWS_MOBILE -# include // For TerminateProcess() -#elif GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +# include # include # include +# include // Used in ThreadLocal. +# ifdef _MSC_VER +# include +# endif // _MSC_VER #else # include -#endif // GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC # include @@ -51,24 +55,35 @@ # include #endif // GTEST_OS_MAC +#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD || GTEST_OS_OPENBSD +# include +# if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +# include +# endif +#endif + #if GTEST_OS_QNX # include +# include # include #endif // GTEST_OS_QNX +#if GTEST_OS_AIX +# include +# include +#endif // GTEST_OS_AIX + +#if GTEST_OS_FUCHSIA +# include +# include +#endif // GTEST_OS_FUCHSIA + #include "gtest/gtest-spi.h" #include "gtest/gtest-message.h" #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { @@ -82,10 +97,31 @@ const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER -#if GTEST_OS_MAC +#if GTEST_OS_LINUX + +namespace { +template +T ReadProcFileField(const std::string& filename, int field) { + std::string dummy; + std::ifstream file(filename.c_str()); + while (field-- > 0) { + file >> dummy; + } + T output = 0; + file >> output; + return output; +} +} // namespace + +// Returns the number of active threads, or 0 when there is an error. +size_t GetThreadCount() { + const std::string filename = + (Message() << "/proc/" << getpid() << "/stat").GetString(); + return ReadProcFileField(filename, 19); +} + +#elif GTEST_OS_MAC -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; @@ -103,6 +139,81 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD + +#if GTEST_OS_NETBSD +#undef KERN_PROC +#define KERN_PROC KERN_PROC2 +#define kinfo_proc kinfo_proc2 +#endif + +#if GTEST_OS_DRAGONFLY +#define KP_NLWP(kp) (kp.kp_nthreads) +#elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +#define KP_NLWP(kp) (kp.ki_numthreads) +#elif GTEST_OS_NETBSD +#define KP_NLWP(kp) (kp.p_nlwps) +#endif + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID, + getpid(), +#if GTEST_OS_NETBSD + sizeof(struct kinfo_proc), + 1, +#endif + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + struct kinfo_proc info; + size_t size = sizeof(info); + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + return static_cast(KP_NLWP(info)); +} +#elif GTEST_OS_OPENBSD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID | KERN_PROC_SHOW_THREADS, + getpid(), + sizeof(struct kinfo_proc), + 0, + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + + // get number of structs + size_t size; + if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { + return 0; + } + mib[5] = size / mib[4]; + + // populate array of structs + struct kinfo_proc info[mib[5]]; + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + + // exclude empty members + int nthreads = 0; + for (int i = 0; i < size / mib[4]; i++) { + if (info[i].p_tid != -1) + nthreads++; + } + return nthreads; +} + #elif GTEST_OS_QNX // Returns the number of threads running in the process, or 0 to indicate that @@ -114,7 +225,7 @@ size_t GetThreadCount() { } procfs_info process_info; const int status = - devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); + devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), nullptr); close(fd); if (status == EOK) { return static_cast(process_info.num_threads); @@ -123,6 +234,38 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_AIX + +size_t GetThreadCount() { + struct procentry64 entry; + pid_t pid = getpid(); + int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1); + if (status == 1) { + return entry.pi_thcount; + } else { + return 0; + } +} + +#elif GTEST_OS_FUCHSIA + +size_t GetThreadCount() { + int dummy_buffer; + size_t avail; + zx_status_t status = zx_object_get_info( + zx_process_self(), + ZX_INFO_PROCESS_THREADS, + &dummy_buffer, + 0, + nullptr, + &avail); + if (status == ZX_OK) { + return avail; + } else { + return 0; + } +} + #else size_t GetThreadCount() { @@ -131,7 +274,430 @@ size_t GetThreadCount() { return 0; } -#endif // GTEST_OS_MAC +#endif // GTEST_OS_LINUX + +#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS + +void SleepMilliseconds(int n) { + ::Sleep(static_cast(n)); +} + +AutoHandle::AutoHandle() + : handle_(INVALID_HANDLE_VALUE) {} + +AutoHandle::AutoHandle(Handle handle) + : handle_(handle) {} + +AutoHandle::~AutoHandle() { + Reset(); +} + +AutoHandle::Handle AutoHandle::Get() const { + return handle_; +} + +void AutoHandle::Reset() { + Reset(INVALID_HANDLE_VALUE); +} + +void AutoHandle::Reset(HANDLE handle) { + // Resetting with the same handle we already own is invalid. + if (handle_ != handle) { + if (IsCloseable()) { + ::CloseHandle(handle_); + } + handle_ = handle; + } else { + GTEST_CHECK_(!IsCloseable()) + << "Resetting a valid handle to itself is likely a programmer error " + "and thus not allowed."; + } +} + +bool AutoHandle::IsCloseable() const { + // Different Windows APIs may use either of these values to represent an + // invalid handle. + return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE; +} + +Notification::Notification() + : event_(::CreateEvent(nullptr, // Default security attributes. + TRUE, // Do not reset automatically. + FALSE, // Initially unset. + nullptr)) { // Anonymous event. + GTEST_CHECK_(event_.Get() != nullptr); +} + +void Notification::Notify() { + GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); +} + +void Notification::WaitForNotification() { + GTEST_CHECK_( + ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); +} + +Mutex::Mutex() + : owner_thread_id_(0), + type_(kDynamic), + critical_section_init_phase_(0), + critical_section_(new CRITICAL_SECTION) { + ::InitializeCriticalSection(critical_section_); +} + +Mutex::~Mutex() { + // Static mutexes are leaked intentionally. It is not thread-safe to try + // to clean them up. + if (type_ == kDynamic) { + ::DeleteCriticalSection(critical_section_); + delete critical_section_; + critical_section_ = nullptr; + } +} + +void Mutex::Lock() { + ThreadSafeLazyInit(); + ::EnterCriticalSection(critical_section_); + owner_thread_id_ = ::GetCurrentThreadId(); +} + +void Mutex::Unlock() { + ThreadSafeLazyInit(); + // We don't protect writing to owner_thread_id_ here, as it's the + // caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_thread_id_ = 0; + ::LeaveCriticalSection(critical_section_); +} + +// Does nothing if the current thread holds the mutex. Otherwise, crashes +// with high probability. +void Mutex::AssertHeld() { + ThreadSafeLazyInit(); + GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) + << "The current thread is not holding the mutex @" << this; +} + +namespace { + +#ifdef _MSC_VER +// Use the RAII idiom to flag mem allocs that are intentionally never +// deallocated. The motivation is to silence the false positive mem leaks +// that are reported by the debug version of MS's CRT which can only detect +// if an alloc is missing a matching deallocation. +// Example: +// MemoryIsNotDeallocated memory_is_not_deallocated; +// critical_section_ = new CRITICAL_SECTION; +// +class MemoryIsNotDeallocated +{ + public: + MemoryIsNotDeallocated() : old_crtdbg_flag_(0) { + old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT + // doesn't report mem leak if there's no matching deallocation. + _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF); + } + + ~MemoryIsNotDeallocated() { + // Restore the original _CRTDBG_ALLOC_MEM_DF flag + _CrtSetDbgFlag(old_crtdbg_flag_); + } + + private: + int old_crtdbg_flag_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated); +}; +#endif // _MSC_VER + +} // namespace + +// Initializes owner_thread_id_ and critical_section_ in static mutexes. +void Mutex::ThreadSafeLazyInit() { + // Dynamic mutexes are initialized in the constructor. + if (type_ == kStatic) { + switch ( + ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { + case 0: + // If critical_section_init_phase_ was 0 before the exchange, we + // are the first to test it and need to perform the initialization. + owner_thread_id_ = 0; + { + // Use RAII to flag that following mem alloc is never deallocated. +#ifdef _MSC_VER + MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER + critical_section_ = new CRITICAL_SECTION; + } + ::InitializeCriticalSection(critical_section_); + // Updates the critical_section_init_phase_ to 2 to signal + // initialization complete. + GTEST_CHECK_(::InterlockedCompareExchange( + &critical_section_init_phase_, 2L, 1L) == + 1L); + break; + case 1: + // Somebody else is already initializing the mutex; spin until they + // are done. + while (::InterlockedCompareExchange(&critical_section_init_phase_, + 2L, + 2L) != 2L) { + // Possibly yields the rest of the thread's time slice to other + // threads. + ::Sleep(0); + } + break; + + case 2: + break; // The mutex is already initialized and ready for use. + + default: + GTEST_CHECK_(false) + << "Unexpected value of critical_section_init_phase_ " + << "while initializing a static mutex."; + } + } +} + +namespace { + +class ThreadWithParamSupport : public ThreadWithParamBase { + public: + static HANDLE CreateThread(Runnable* runnable, + Notification* thread_can_start) { + ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); + DWORD thread_id; + HANDLE thread_handle = ::CreateThread( + nullptr, // Default security. + 0, // Default stack size. + &ThreadWithParamSupport::ThreadMain, + param, // Parameter to ThreadMainStatic + 0x0, // Default creation flags. + &thread_id); // Need a valid pointer for the call to work under Win98. + GTEST_CHECK_(thread_handle != nullptr) + << "CreateThread failed with error " << ::GetLastError() << "."; + if (thread_handle == nullptr) { + delete param; + } + return thread_handle; + } + + private: + struct ThreadMainParam { + ThreadMainParam(Runnable* runnable, Notification* thread_can_start) + : runnable_(runnable), + thread_can_start_(thread_can_start) { + } + std::unique_ptr runnable_; + // Does not own. + Notification* thread_can_start_; + }; + + static DWORD WINAPI ThreadMain(void* ptr) { + // Transfers ownership. + std::unique_ptr param(static_cast(ptr)); + if (param->thread_can_start_ != nullptr) + param->thread_can_start_->WaitForNotification(); + param->runnable_->Run(); + return 0; + } + + // Prohibit instantiation. + ThreadWithParamSupport(); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); +}; + +} // namespace + +ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, + Notification* thread_can_start) + : thread_(ThreadWithParamSupport::CreateThread(runnable, + thread_can_start)) { +} + +ThreadWithParamBase::~ThreadWithParamBase() { + Join(); +} + +void ThreadWithParamBase::Join() { + GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) + << "Failed to join the thread with error " << ::GetLastError() << "."; +} + +// Maps a thread to a set of ThreadIdToThreadLocals that have values +// instantiated on that thread and notifies them when the thread exits. A +// ThreadLocal instance is expected to persist until all threads it has +// values on have terminated. +class ThreadLocalRegistryImpl { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + DWORD current_thread = ::GetCurrentThreadId(); + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(current_thread); + if (thread_local_pos == thread_to_thread_locals->end()) { + thread_local_pos = thread_to_thread_locals->insert( + std::make_pair(current_thread, ThreadLocalValues())).first; + StartWatcherThreadFor(current_thread); + } + ThreadLocalValues& thread_local_values = thread_local_pos->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos == thread_local_values.end()) { + value_pos = + thread_local_values + .insert(std::make_pair( + thread_local_instance, + std::shared_ptr( + thread_local_instance->NewValueForCurrentThread()))) + .first; + } + return value_pos->second.get(); + } + + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + std::vector > value_holders; + // Clean up the ThreadLocalValues data structure while holding the lock, but + // defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + for (ThreadIdToThreadLocals::iterator it = + thread_to_thread_locals->begin(); + it != thread_to_thread_locals->end(); + ++it) { + ThreadLocalValues& thread_local_values = it->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos != thread_local_values.end()) { + value_holders.push_back(value_pos->second); + thread_local_values.erase(value_pos); + // This 'if' can only be successful at most once, so theoretically we + // could break out of the loop here, but we don't bother doing so. + } + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + static void OnThreadExit(DWORD thread_id) { + GTEST_CHECK_(thread_id != 0) << ::GetLastError(); + std::vector > value_holders; + // Clean up the ThreadIdToThreadLocals data structure while holding the + // lock, but defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(thread_id); + if (thread_local_pos != thread_to_thread_locals->end()) { + ThreadLocalValues& thread_local_values = thread_local_pos->second; + for (ThreadLocalValues::iterator value_pos = + thread_local_values.begin(); + value_pos != thread_local_values.end(); + ++value_pos) { + value_holders.push_back(value_pos->second); + } + thread_to_thread_locals->erase(thread_local_pos); + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + private: + // In a particular thread, maps a ThreadLocal object to its value. + typedef std::map > + ThreadLocalValues; + // Stores all ThreadIdToThreadLocals having values in a thread, indexed by + // thread's ID. + typedef std::map ThreadIdToThreadLocals; + + // Holds the thread id and thread handle that we pass from + // StartWatcherThreadFor to WatcherThreadFunc. + typedef std::pair ThreadIdAndHandle; + + static void StartWatcherThreadFor(DWORD thread_id) { + // The returned handle will be kept in thread_map and closed by + // watcher_thread in WatcherThreadFunc. + HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, + FALSE, + thread_id); + GTEST_CHECK_(thread != nullptr); + // We need to pass a valid thread ID pointer into CreateThread for it + // to work correctly under Win98. + DWORD watcher_thread_id; + HANDLE watcher_thread = ::CreateThread( + nullptr, // Default security. + 0, // Default stack size + &ThreadLocalRegistryImpl::WatcherThreadFunc, + reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), + CREATE_SUSPENDED, &watcher_thread_id); + GTEST_CHECK_(watcher_thread != nullptr); + // Give the watcher thread the same priority as ours to avoid being + // blocked by it. + ::SetThreadPriority(watcher_thread, + ::GetThreadPriority(::GetCurrentThread())); + ::ResumeThread(watcher_thread); + ::CloseHandle(watcher_thread); + } + + // Monitors exit from a given thread and notifies those + // ThreadIdToThreadLocals about thread termination. + static DWORD WINAPI WatcherThreadFunc(LPVOID param) { + const ThreadIdAndHandle* tah = + reinterpret_cast(param); + GTEST_CHECK_( + ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); + OnThreadExit(tah->first); + ::CloseHandle(tah->second); + delete tah; + return 0; + } + + // Returns map of thread local instances. + static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { + mutex_.AssertHeld(); +#ifdef _MSC_VER + MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER + static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); + return map; + } + + // Protects access to GetThreadLocalsMapLocked() and its return value. + static Mutex mutex_; + // Protects access to GetThreadMapLocked() and its return value. + static Mutex thread_map_mutex_; +}; + +Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); +Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); + +ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + return ThreadLocalRegistryImpl::GetValueOnCurrentThread( + thread_local_instance); +} + +void ThreadLocalRegistry::OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); +} + +#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS #if GTEST_USES_POSIX_RE @@ -149,7 +715,7 @@ RE::~RE() { free(const_cast(pattern_)); } -// Returns true iff regular expression re matches the entire str. +// Returns true if and only if regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; @@ -157,8 +723,8 @@ bool RE::FullMatch(const char* str, const RE& re) { return regexec(&re.full_regex_, str, 1, &match, 0) == 0; } -// Returns true iff regular expression re matches a substring of str -// (including str itself). +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; @@ -198,14 +764,14 @@ void RE::Init(const char* regex) { #elif GTEST_USES_SIMPLE_RE -// Returns true iff ch appears anywhere in str (excluding the +// Returns true if and only if ch appears anywhere in str (excluding the // terminating '\0' character). bool IsInSet(char ch, const char* str) { - return ch != '\0' && strchr(str, ch) != NULL; + return ch != '\0' && strchr(str, ch) != nullptr; } -// Returns true iff ch belongs to the given classification. Unlike -// similar functions in , these aren't affected by the +// Returns true if and only if ch belongs to the given classification. +// Unlike similar functions in , these aren't affected by the // current locale. bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsAsciiPunct(char ch) { @@ -218,13 +784,13 @@ bool IsAsciiWordChar(char ch) { ('0' <= ch && ch <= '9') || ch == '_'; } -// Returns true iff "\\c" is a supported escape sequence. +// Returns true if and only if "\\c" is a supported escape sequence. bool IsValidEscape(char c) { return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); } -// Returns true iff the given atom (specified by escaped and pattern) -// matches ch. The result is undefined if the atom is invalid. +// Returns true if and only if the given atom (specified by escaped and +// pattern) matches ch. The result is undefined if the atom is invalid. bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { @@ -247,7 +813,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { } // Helper function used by ValidateRegex() to format error messages. -std::string FormatRegexSyntaxError(const char* regex, int index) { +static std::string FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } @@ -255,17 +821,14 @@ std::string FormatRegexSyntaxError(const char* regex, int index) { // Generates non-fatal failures and returns false if regex is invalid; // otherwise returns true. bool ValidateRegex(const char* regex) { - if (regex == NULL) { - // TODO(wan@google.com): fix the source file location in the - // assertion failures to match where the regex is used in user - // code. + if (regex == nullptr) { ADD_FAILURE() << "NULL is not a valid simple regular expression."; return false; } bool is_valid = true; - // True iff ?, *, or + can follow the previous atom. + // True if and only if ?, *, or + can follow the previous atom. bool prev_repeatable = false; for (int i = 0; regex[i]; i++) { if (regex[i] == '\\') { // An escape sequence @@ -341,8 +904,8 @@ bool MatchRepetitionAndRegexAtHead( return false; } -// Returns true iff regex matches a prefix of str. regex must be a -// valid simple regular expression and not start with "^", or the +// Returns true if and only if regex matches a prefix of str. regex must +// be a valid simple regular expression and not start with "^", or the // result is undefined. bool MatchRegexAtHead(const char* regex, const char* str) { if (*regex == '\0') // An empty regex matches a prefix of anything. @@ -372,8 +935,8 @@ bool MatchRegexAtHead(const char* regex, const char* str) { } } -// Returns true iff regex matches any substring of str. regex must be -// a valid simple regular expression, or the result is undefined. +// Returns true if and only if regex matches any substring of str. regex must +// be a valid simple regular expression, or the result is undefined. // // The algorithm is recursive, but the recursion depth doesn't exceed // the regex length, so we won't need to worry about running out of @@ -381,8 +944,7 @@ bool MatchRegexAtHead(const char* regex, const char* str) { // exponential with respect to the regex length + the string length, // but usually it's must faster (often close to linear). bool MatchRegexAnywhere(const char* regex, const char* str) { - if (regex == NULL || str == NULL) - return false; + if (regex == nullptr || str == nullptr) return false; if (*regex == '^') return MatchRegexAtHead(regex + 1, str); @@ -402,21 +964,21 @@ RE::~RE() { free(const_cast(full_pattern_)); } -// Returns true iff regular expression re matches the entire str. +// Returns true if and only if regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); } -// Returns true iff regular expression re matches a substring of str -// (including str itself). +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); } // Initializes an RE from its string representation. void RE::Init(const char* regex) { - pattern_ = full_pattern_ = NULL; - if (regex != NULL) { + pattern_ = full_pattern_ = nullptr; + if (regex != nullptr) { pattern_ = posix::StrDup(regex); } @@ -454,7 +1016,7 @@ const char kUnknownFile[] = "unknown file"; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); + const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) { return file_name + ":"; @@ -473,7 +1035,7 @@ GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { // to the file location it produces, unlike FormatFileLocation(). GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); + const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) return file_name; @@ -481,7 +1043,6 @@ GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( return file_name + ":" + StreamableToString(line); } - GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { const char* const marker = @@ -500,12 +1061,10 @@ GTestLog::~GTestLog() { posix::Abort(); } } + // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4996) -#endif // _MSC_VER +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() #if GTEST_HAS_STREAM_REDIRECTION @@ -543,20 +1102,22 @@ class CapturedStream { // code as part of a regular standalone executable, which doesn't // run in a Dalvik process (e.g. when running it through 'adb shell'). // - // The location /sdcard is directly accessible from native code - // and is the only location (unofficially) supported by the Android - // team. It's generally a symlink to the real SD Card mount point - // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or - // other OEM-customized locations. Never rely on these, and always - // use /sdcard. - char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; + // The location /data/local/tmp is directly accessible from native code. + // '/sdcard' and other variants cannot be relied on, as they are not + // guaranteed to be mounted, or may have a delay in mounting. + char name_template[] = "/data/local/tmp/gtest_captured_stream.XXXXXX"; # else char name_template[] = "/tmp/captured_stream.XXXXXX"; # endif // GTEST_OS_LINUX_ANDROID const int captured_fd = mkstemp(name_template); + if (captured_fd == -1) { + GTEST_LOG_(WARNING) + << "Failed to create tmp file " << name_template + << " for test; does the test have access to the /tmp directory?"; + } filename_ = name_template; # endif // GTEST_OS_WINDOWS - fflush(NULL); + fflush(nullptr); dup2(captured_fd, fd_); close(captured_fd); } @@ -568,25 +1129,23 @@ class CapturedStream { std::string GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. - fflush(NULL); + fflush(nullptr); dup2(uncaptured_fd_, fd_); close(uncaptured_fd_); uncaptured_fd_ = -1; } FILE* const file = posix::FOpen(filename_.c_str(), "r"); + if (file == nullptr) { + GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_ + << " for capturing stream."; + } const std::string content = ReadEntireFile(file); posix::FClose(file); return content; } private: - // Reads the entire content of a file as an std::string. - static std::string ReadEntireFile(FILE* file); - - // Returns the size (in bytes) of a file. - static size_t GetFileSize(FILE* file); - const int fd_; // A stream to capture. int uncaptured_fd_; // Name of the temporary file holding the stderr output. @@ -595,45 +1154,15 @@ class CapturedStream { GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; -// Returns the size (in bytes) of a file. -size_t CapturedStream::GetFileSize(FILE* file) { - fseek(file, 0, SEEK_END); - return static_cast(ftell(file)); -} +GTEST_DISABLE_MSC_DEPRECATED_POP_() -// Reads the entire content of a file as a string. -std::string CapturedStream::ReadEntireFile(FILE* file) { - const size_t file_size = GetFileSize(file); - char* const buffer = new char[file_size]; - - size_t bytes_last_read = 0; // # of bytes read in the last fread() - size_t bytes_read = 0; // # of bytes read so far - - fseek(file, 0, SEEK_SET); - - // Keeps reading the file until we cannot read further or the - // pre-determined file size is reached. - do { - bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); - bytes_read += bytes_last_read; - } while (bytes_last_read > 0 && bytes_read < file_size); - - const std::string content(buffer, bytes_read); - delete[] buffer; - - return content; -} - -# ifdef _MSC_VER -# pragma warning(pop) -# endif // _MSC_VER - -static CapturedStream* g_captured_stderr = NULL; -static CapturedStream* g_captured_stdout = NULL; +static CapturedStream* g_captured_stderr = nullptr; +static CapturedStream* g_captured_stdout = nullptr; // Starts capturing an output stream (stdout/stderr). -void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { - if (*stream != NULL) { +static void CaptureStream(int fd, const char* stream_name, + CapturedStream** stream) { + if (*stream != nullptr) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; } @@ -641,11 +1170,11 @@ void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { } // Stops capturing the output stream and returns the captured string. -std::string GetCapturedStream(CapturedStream** captured_stream) { +static std::string GetCapturedStream(CapturedStream** captured_stream) { const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; - *captured_stream = NULL; + *captured_stream = nullptr; return content; } @@ -672,25 +1201,61 @@ std::string GetCapturedStderr() { #endif // GTEST_HAS_STREAM_REDIRECTION -#if GTEST_HAS_DEATH_TEST -// A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; -static const ::std::vector* g_injected_test_argvs = - NULL; // Owned. -void SetInjectableArgvs(const ::std::vector* argvs) { - if (g_injected_test_argvs != argvs) - delete g_injected_test_argvs; - g_injected_test_argvs = argvs; + +size_t GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); } -const ::std::vector& GetInjectableArgvs() { - if (g_injected_test_argvs != NULL) { +std::string ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const std::string content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +#if GTEST_HAS_DEATH_TEST +static const std::vector* g_injected_test_argvs = + nullptr; // Owned. + +std::vector GetInjectableArgvs() { + if (g_injected_test_argvs != nullptr) { return *g_injected_test_argvs; } - return g_argvs; + return GetArgvs(); +} + +void SetInjectableArgvs(const std::vector* new_argvs) { + if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs; + g_injected_test_argvs = new_argvs; +} + +void SetInjectableArgvs(const std::vector& new_argvs) { + SetInjectableArgvs( + new std::vector(new_argvs.begin(), new_argvs.end())); +} + +void ClearInjectableArgvs() { + delete g_injected_test_argvs; + g_injected_test_argvs = nullptr; } #endif // GTEST_HAS_DEATH_TEST @@ -723,7 +1288,7 @@ static std::string FlagToEnvVar(const char* flag) { // unchanged and returns false. bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Parses the environment variable as a decimal integer. - char* end = NULL; + char* end = nullptr; const long long_value = strtol(str, &end, 10); // NOLINT // Has strtol() consumed all characters in the string? @@ -762,21 +1327,28 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Reads and returns the Boolean environment variable corresponding to // the given flag; if it's not set, returns default_value. // -// The value is considered true iff it's not "0". +// The value is considered true if and only if it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { +#if defined(GTEST_GET_BOOL_FROM_ENV_) + return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); - return string_value == NULL ? - default_value : strcmp(string_value, "0") != 0; + return string_value == nullptr ? default_value + : strcmp(string_value, "0") != 0; +#endif // defined(GTEST_GET_BOOL_FROM_ENV_) } // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { +#if defined(GTEST_GET_INT32_FROM_ENV_) + return GTEST_GET_INT32_FROM_ENV_(flag, default_value); +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); - if (string_value == NULL) { + if (string_value == nullptr) { // The environment variable is not set. return default_value; } @@ -791,14 +1363,36 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { } return result; +#endif // defined(GTEST_GET_INT32_FROM_ENV_) +} + +// As a special case for the 'output' flag, if GTEST_OUTPUT is not +// set, we look for XML_OUTPUT_FILE, which is set by the Bazel build +// system. The value of XML_OUTPUT_FILE is a filename without the +// "xml:" prefix of GTEST_OUTPUT. +// Note that this is meant to be called at the call site so it does +// not check that the flag is 'output' +// In essence this checks an env variable called XML_OUTPUT_FILE +// and if it is set we prepend "xml:" to its value, if it not set we return "" +std::string OutputFlagAlsoCheckEnvVar(){ + std::string default_value_for_output_flag = ""; + const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); + if (nullptr != xml_output_file_env) { + default_value_for_output_flag = std::string("xml:") + xml_output_file_env; + } + return default_value_for_output_flag; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { +#if defined(GTEST_GET_STRING_FROM_ENV_) + return GTEST_GET_STRING_FROM_ENV_(flag, default_value); +#else const std::string env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); - return value == NULL ? default_value : value; + return value == nullptr ? default_value : value; +#endif // defined(GTEST_GET_STRING_FROM_ENV_) } } // namespace internal diff --git a/test/gtest/src/gtest-printers.cc b/test/gtest/src/gtest-printers.cc index 75fa408100..3337be312e 100644 --- a/test/gtest/src/gtest-printers.cc +++ b/test/gtest/src/gtest-printers.cc @@ -26,10 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -43,11 +42,13 @@ // defines Foo. #include "gtest/gtest-printers.h" -#include #include +#include +#include #include // NOLINT #include #include "gtest/internal/gtest-port.h" +#include "src/gtest-internal-inl.h" namespace testing { @@ -56,6 +57,10 @@ namespace { using ::std::ostream; // Prints a segment of bytes in the given object. +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; @@ -85,7 +90,6 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. - // TODO(wan): let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { @@ -119,7 +123,7 @@ namespace internal { // Depending on the value of a char (or wchar_t), we print it in one // of three formats: // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), -// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a hexadecimal escape sequence (e.g. '\x7F'), or // - as a special escape sequence (e.g. '\r', '\n'). enum CharFormat { kAsIs, @@ -140,7 +144,8 @@ inline bool IsPrintableAscii(wchar_t c) { // which is the type of c. template static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { - switch (static_cast(c)) { + wchar_t w_c = static_cast(c); + switch (w_c) { case L'\0': *os << "\\0"; break; @@ -172,11 +177,14 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { *os << "\\v"; break; default: - if (IsPrintableAscii(c)) { + if (IsPrintableAscii(w_c)) { *os << static_cast(c); return kAsIs; } else { - *os << "\\x" + String::FormatHexInt(static_cast(c)); + ostream::fmtflags flags = os->flags(); + *os << "\\x" << std::hex << std::uppercase + << static_cast(static_cast(c)); + os->flags(flags); return kHexEscape; } } @@ -223,13 +231,13 @@ void PrintCharAndCodeTo(Char c, ostream* os) { return; *os << " (" << static_cast(c); - // For more convenience, we print c's code again in hexidecimal, + // For more convenience, we print c's code again in hexadecimal, // unless c was already printed in the form '\x##' or the code is in // [1, 9]. if (format == kHexEscape || (1 <= c && c <= 9)) { // Do nothing. } else { - *os << ", 0x" << String::FormatHexInt(static_cast(c)); + *os << ", 0x" << String::FormatHexInt(static_cast(c)); } *os << ")"; } @@ -252,11 +260,16 @@ void PrintTo(wchar_t wc, ostream* os) { // The array starts at begin, the length is len, it may include '\0' characters // and may not be NUL-terminated. template -static void PrintCharsAsStringTo( +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +static CharFormat PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; + CharFormat print_format = kAsIs; for (size_t index = 0; index < len; ++index) { const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(cur)) { @@ -266,13 +279,22 @@ static void PrintCharsAsStringTo( *os << "\" " << kQuoteBegin; } is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; + // Remember if any characters required hex escaping. + if (is_previous_hex) { + print_format = kHexEscape; + } } *os << "\""; + return print_format; } // Prints a (const) char/wchar_t array of 'len' elements, starting at address // 'begin'. CharType must be either char or wchar_t. template +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code @@ -308,7 +330,7 @@ void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { // Prints the given C string to the ostream. void PrintTo(const char* s, ostream* os) { - if (s == NULL) { + if (s == nullptr) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; @@ -325,7 +347,7 @@ void PrintTo(const char* s, ostream* os) { #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Prints the given wide C string to the ostream. void PrintTo(const wchar_t* s, ostream* os) { - if (s == NULL) { + if (s == nullptr) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; @@ -334,23 +356,80 @@ void PrintTo(const wchar_t* s, ostream* os) { } #endif // wchar_t is native -// Prints a ::string object. -#if GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); +namespace { + +bool ContainsUnprintableControlCodes(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length; i++) { + unsigned char ch = *s++; + if (std::iscntrl(ch)) { + switch (ch) { + case '\t': + case '\n': + case '\r': + break; + default: + return true; + } + } + } + return false; } -#endif // GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::std::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); +bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; } + +bool IsValidUTF8(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length;) { + unsigned char lead = s[i++]; + + if (lead <= 0x7f) { + continue; // single-byte character (ASCII) 0..7F + } + if (lead < 0xc2) { + return false; // trail byte or non-shortest form + } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) { + ++i; // 2-byte character + } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + // check for non-shortest form and surrogate + (lead != 0xe0 || s[i] >= 0xa0) && + (lead != 0xed || s[i] < 0xa0)) { + i += 2; // 3-byte character + } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + IsUTF8TrailByte(s[i + 2]) && + // check for non-shortest form + (lead != 0xf0 || s[i] >= 0x90) && + (lead != 0xf4 || s[i] < 0x90)) { + i += 3; // 4-byte character + } else { + return false; + } + } + return true; } -// Prints a ::wstring object. -#if GTEST_HAS_GLOBAL_WSTRING -void PrintWideStringTo(const ::wstring& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); +void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { + if (!ContainsUnprintableControlCodes(str, length) && + IsValidUTF8(str, length)) { + *os << "\n As Text: \"" << str << "\""; + } +} + +} // anonymous namespace + +void PrintStringTo(const ::std::string& s, ostream* os) { + if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { + if (GTEST_FLAG(print_utf8)) { + ConditionalPrintAsText(s.data(), s.size(), os); + } + } } -#endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING void PrintWideStringTo(const ::std::wstring& s, ostream* os) { diff --git a/test/gtest/src/gtest-test-part.cc b/test/gtest/src/gtest-test-part.cc index c60eef3ab3..178317a6bc 100644 --- a/test/gtest/src/gtest-test-part.cc +++ b/test/gtest/src/gtest-test-part.cc @@ -26,21 +26,12 @@ // 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. + // -// Author: mheule@google.com (Markus Heule) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest-test-part.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { @@ -50,18 +41,21 @@ using internal::GetUnitTestImpl; // in it. std::string TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); - return stack_trace == NULL ? message : - std::string(message, stack_trace); + return stack_trace == nullptr ? message : std::string(message, stack_trace); } // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os - << result.file_name() << ":" << result.line_number() << ": " - << (result.type() == TestPartResult::kSuccess ? "Success" : - result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; + return os << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess + ? "Success" + : result.type() == TestPartResult::kSkip + ? "Skipped" + : result.type() == TestPartResult::kFatalFailure + ? "Fatal failure" + : "Non-fatal failure") + << ":\n" + << result.message() << std::endl; } // Appends a TestPartResult to the array. @@ -76,7 +70,7 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { internal::posix::Abort(); } - return array_[index]; + return array_[static_cast(index)]; } // Returns the number of TestPartResult objects in the array. diff --git a/test/gtest/src/gtest-typed-test.cc b/test/gtest/src/gtest-typed-test.cc index f0079f407c..8677caf732 100644 --- a/test/gtest/src/gtest-typed-test.cc +++ b/test/gtest/src/gtest-typed-test.cc @@ -26,10 +26,10 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + #include "gtest/gtest-typed-test.h" + #include "gtest/gtest.h" namespace testing { @@ -45,33 +45,41 @@ static const char* SkipSpaces(const char* str) { return str; } +static std::vector SplitIntoTestNames(const char* src) { + std::vector name_vec; + src = SkipSpaces(src); + for (; src != nullptr; src = SkipComma(src)) { + name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); + } + return name_vec; +} + // Verifies that registered_tests match the test names in -// defined_test_names_; returns registered_tests if successful, or +// registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. -const char* TypedTestCasePState::VerifyRegisteredTestNames( +const char* TypedTestSuitePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { - typedef ::std::set::const_iterator DefinedTestIter; + typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; - // Skip initial whitespace in registered_tests since some - // preprocessors prefix stringizied literals with whitespace. - registered_tests = SkipSpaces(registered_tests); + std::vector name_vec = SplitIntoTestNames(registered_tests); Message errors; - ::std::set tests; - for (const char* names = registered_tests; names != NULL; - names = SkipComma(names)) { - const std::string name = GetPrefixUntilComma(names); + + std::set tests; + for (std::vector::const_iterator name_it = name_vec.begin(); + name_it != name_vec.end(); ++name_it) { + const std::string& name = *name_it; if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; } bool found = false; - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); ++it) { - if (name == *it) { + if (name == it->first) { found = true; break; } @@ -81,15 +89,15 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( tests.insert(name); } else { errors << "No test named " << name - << " can be found in this test case.\n"; + << " can be found in this test suite.\n"; } } - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); ++it) { - if (tests.count(*it) == 0) { - errors << "You forgot to list test " << *it << ".\n"; + if (tests.count(it->first) == 0) { + errors << "You forgot to list test " << it->first << ".\n"; } } diff --git a/test/gtest/src/gtest.cc b/test/gtest/src/gtest.cc index 7ee9368320..1dff1a6afb 100644 --- a/test/gtest/src/gtest.cc +++ b/test/gtest/src/gtest.cc @@ -26,14 +26,17 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest.h" +#include "gtest/internal/custom/gtest.h" #include "gtest/gtest-spi.h" + +#ifndef _WIN32 #pragma GCC system_header +#endif #include #include @@ -47,14 +50,14 @@ #include #include #include +#include +#include #include // NOLINT #include #include #if GTEST_OS_LINUX -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT @@ -67,10 +70,6 @@ # include // NOLINT # include -#elif GTEST_OS_SYMBIAN -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT - #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT @@ -81,9 +80,15 @@ #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT +# undef min #elif GTEST_OS_WINDOWS // We are on Windows proper. +# include // NOLINT +# undef min + +# include // NOLINT +# include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT @@ -91,24 +96,13 @@ # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -// TODO(kenton@google.com): There are other ways to get the time on -// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW -// supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # endif // GTEST_OS_WINDOWS_MINGW -// cpplint thinks that the header is already included, so we want to -// silence it. -# include // NOLINT - #else // Assume other platforms have gettimeofday(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to @@ -125,21 +119,29 @@ #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT +# include // NOLINT +# include // NOLINT #endif -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS +#include +#endif +#endif + +#if GTEST_HAS_ABSL +#include "absl/debugging/failure_signal_handler.h" +#include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" +#include "absl/strings/str_cat.h" +#endif // GTEST_HAS_ABSL + namespace testing { using internal::CountIf; @@ -149,20 +151,22 @@ using internal::Shuffle; // Constants. -// A test whose test case name or test name matches this filter is +// A test whose test suite name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; -// A test case whose name matches this filter is considered a death -// test case and will be run before test cases whose name doesn't +// A test suite whose name matches this filter is considered a death +// test suite and will be run before test suites whose name doesn't // match this filter. -static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; +static const char kDeathTestSuiteFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; -// The default output file for XML output. -static const char kDefaultOutputFile[] = "test_detail.xml"; +// The default output format. +static const char kDefaultOutputFormat[] = "xml"; +// The default output file. +static const char kDefaultOutputFile[] = "test_detail"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; @@ -177,13 +181,35 @@ namespace internal { // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. bool g_help_flag = false; +// Utilty function to Open File for Writing +static FILE* OpenFileForWriting(const std::string& output_file) { + FILE* fileout = nullptr; + FilePath output_file_path(output_file); + FilePath output_dir(output_file_path.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + fileout = posix::FOpen(output_file.c_str(), "w"); + } + if (fileout == nullptr) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\""; + } + return fileout; +} + } // namespace internal +// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY +// environment variable. static const char* GetDefaultFilter() { + const char* const testbridge_test_only = + internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY"); + if (testbridge_test_only != nullptr) { + return testbridge_test_only; + } return kUniversalFilter; } @@ -193,15 +219,14 @@ GTEST_DEFINE_bool_( "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( - break_on_failure, - internal::BoolFromGTestEnv("break_on_failure", false), - "True iff a failed assertion should be a debugger break-point."); + break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), + "True if and only if a failed assertion should be a debugger " + "break-point."); -GTEST_DEFINE_bool_( - catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", true), - "True iff " GTEST_NAME_ - " should catch exceptions and treat them as test failures."); +GTEST_DEFINE_bool_(catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True if and only if " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, @@ -220,26 +245,41 @@ GTEST_DEFINE_string_( "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); +GTEST_DEFINE_bool_( + install_failure_signal_handler, + internal::BoolFromGTestEnv("install_failure_signal_handler", false), + "If true and supported on the current platform, " GTEST_NAME_ " should " + "install a signal handler that dumps debugging information when fatal " + "signals are raised."); + GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); +// The net priority order after flag processing is thus: +// --gtest_output command line flag +// GTEST_OUTPUT environment variable +// XML_OUTPUT_FILE environment variable +// '' GTEST_DEFINE_string_( output, - internal::StringFromGTestEnv("output", ""), - "A format (currently must be \"xml\"), optionally followed " - "by a colon and an output file name or directory. A directory " - "is indicated by a trailing pathname separator. " + internal::StringFromGTestEnv("output", + internal::OutputFlagAlsoCheckEnvVar().c_str()), + "A format (defaults to \"xml\" but can be specified to be \"json\"), " + "optionally followed by a colon and an output file name or directory. " + "A directory is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " "executable's name and, if necessary, made unique by adding " "digits."); -GTEST_DEFINE_bool_( - print_time, - internal::BoolFromGTestEnv("print_time", true), - "True iff " GTEST_NAME_ - " should display elapsed time in text output."); +GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true), + "True if and only if " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_bool_(print_utf8, internal::BoolFromGTestEnv("print_utf8", true), + "True if and only if " GTEST_NAME_ + " prints UTF8 characters as text."); GTEST_DEFINE_int32_( random_seed, @@ -253,16 +293,14 @@ GTEST_DEFINE_int32_( "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); -GTEST_DEFINE_bool_( - show_internal_stack_frames, false, - "True iff " GTEST_NAME_ " should include internal stack frames when " - "printing test failure stack traces."); +GTEST_DEFINE_bool_(show_internal_stack_frames, false, + "True if and only if " GTEST_NAME_ + " should include internal stack frames when " + "printing test failure stack traces."); -GTEST_DEFINE_bool_( - shuffle, - internal::BoolFromGTestEnv("shuffle", false), - "True iff " GTEST_NAME_ - " should randomize tests' order on every run."); +GTEST_DEFINE_bool_(shuffle, internal::BoolFromGTestEnv("shuffle", false), + "True if and only if " GTEST_NAME_ + " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, @@ -282,7 +320,14 @@ GTEST_DEFINE_bool_( internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " - "otherwise."); + "otherwise. For use with an external test framework."); + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DEFINE_string_( + flagfile, + internal::StringFromGTestEnv("flagfile", ""), + "This flag specifies the flagfile to read command-line flags from."); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ namespace internal { @@ -291,7 +336,8 @@ namespace internal { // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). - state_ = (1103515245U*state_ + 12345U) % kMaxRange; + // Use wider types than necessary to prevent unsigned overflow diagnostics. + state_ = static_cast(1103515245ULL*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; @@ -305,22 +351,16 @@ UInt32 Random::Generate(UInt32 range) { return state_ % range; } -// GTestIsInitialized() returns true iff the user has initialized +// GTestIsInitialized() returns true if and only if the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). -// -// A user must call testing::InitGoogleTest() to initialize Google -// Test. g_init_gtest_count is set to the number of times -// InitGoogleTest() has been called. We don't protect this variable -// under a mutex as it is only accessed in the main thread. -GTEST_API_ int g_init_gtest_count = 0; -static bool GTestIsInitialized() { return g_init_gtest_count != 0; } - -// Iterates over a vector of TestCases, keeping a running sum of the +static bool GTestIsInitialized() { return GetArgvs().size() > 0; } + +// Iterates over a vector of TestSuites, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. -static int SumOverTestCaseList(const std::vector& case_list, - int (TestCase::*method)() const) { +static int SumOverTestSuiteList(const std::vector& case_list, + int (TestSuite::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); @@ -328,20 +368,20 @@ static int SumOverTestCaseList(const std::vector& case_list, return sum; } -// Returns true iff the test case passed. -static bool TestCasePassed(const TestCase* test_case) { - return test_case->should_run() && test_case->Passed(); +// Returns true if and only if the test suite passed. +static bool TestSuitePassed(const TestSuite* test_suite) { + return test_suite->should_run() && test_suite->Passed(); } -// Returns true iff the test case failed. -static bool TestCaseFailed(const TestCase* test_case) { - return test_case->should_run() && test_case->Failed(); +// Returns true if and only if the test suite failed. +static bool TestSuiteFailed(const TestSuite* test_suite) { + return test_suite->should_run() && test_suite->Failed(); } -// Returns true iff test_case contains at least one test that should -// run. -static bool ShouldRunTestCase(const TestCase* test_case) { - return test_case->should_run(); +// Returns true if and only if test_suite contains at least one test that +// should run. +static bool ShouldRunTestSuite(const TestSuite* test_suite) { + return test_suite->should_run(); } // AssertHelper constructor. @@ -367,21 +407,29 @@ void AssertHelper::operator=(const Message& message) const { ); // NOLINT } -// Mutex for linked pointers. -GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); +// A copy of all command line arguments. Set by InitGoogleTest(). +static ::std::vector g_argvs; -// Application pathname gotten in InitGoogleTest. -std::string g_executable_path; +::std::vector GetArgvs() { +#if defined(GTEST_CUSTOM_GET_ARGVS_) + // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or + // ::string. This code converts it to the appropriate type. + const auto& custom = GTEST_CUSTOM_GET_ARGVS_(); + return ::std::vector(custom.begin(), custom.end()); +#else // defined(GTEST_CUSTOM_GET_ARGVS_) + return g_argvs; +#endif // defined(GTEST_CUSTOM_GET_ARGVS_) +} // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; -#if GTEST_OS_WINDOWS - result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#if GTEST_OS_WINDOWS || GTEST_OS_OS2 + result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe")); #else - result.Set(FilePath(g_executable_path)); + result.Set(FilePath(GetArgvs()[0])); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); @@ -392,34 +440,32 @@ FilePath GetCurrentExecutableName() { // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return std::string(""); - const char* const colon = strchr(gtest_output_flag, ':'); - return (colon == NULL) ? - std::string(gtest_output_flag) : - std::string(gtest_output_flag, colon - gtest_output_flag); + return (colon == nullptr) + ? std::string(gtest_output_flag) + : std::string(gtest_output_flag, + static_cast(colon - gtest_output_flag)); } // Returns the name of the requested output file, or the default if none // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) - return ""; + + std::string format = GetOutputFormat(); + if (format.empty()) + format = std::string(kDefaultOutputFormat); const char* const colon = strchr(gtest_output_flag, ':'); - if (colon == NULL) - return internal::FilePath::ConcatPaths( + if (colon == nullptr) + return internal::FilePath::MakeFileName( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).string(); + internal::FilePath(kDefaultOutputFile), 0, + format.c_str()).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) - // TODO(wan@google.com): on Windows \some\path is not an absolute - // path (as its meaning depends on the current drive), yet the - // following logic for turning it into an absolute path is wrong. - // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); @@ -433,8 +479,8 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() { return result.string(); } -// Returns true iff the wildcard pattern matches the string. The -// first ':' or '\0' character in pattern marks the end of it. +// Returns true if and only if the wildcard pattern matches the string. +// The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. @@ -467,7 +513,7 @@ bool UnitTestOptions::MatchesFilter( cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. - if (cur_pattern == NULL) { + if (cur_pattern == nullptr) { return false; } @@ -476,11 +522,11 @@ bool UnitTestOptions::MatchesFilter( } } -// Returns true iff the user-specified filter matches the test case -// name and the test name. -bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name) { - const std::string& full_name = test_case_name + "." + test_name.c_str(); +// Returns true if and only if the user-specified filter matches the test +// suite name and the test name. +bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name, + const std::string& test_name) { + const std::string& full_name = test_suite_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions @@ -488,7 +534,7 @@ bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, const char* const dash = strchr(p, '-'); std::string positive; std::string negative; - if (dash == NULL) { + if (dash == nullptr) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { @@ -607,12 +653,12 @@ extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. -AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, - TestPartResult::Type type, - const string& substr) { +static AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const std::string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); @@ -633,7 +679,7 @@ AssertionResult HasOneFailure(const char* /* results_expr */, << r; } - if (strstr(r.message(), substr.c_str()) == NULL) { + if (strstr(r.message(), substr.c_str()) == nullptr) { return AssertionFailure() << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" @@ -646,13 +692,10 @@ AssertionResult HasOneFailure(const char* /* results_expr */, // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. -SingleFailureChecker:: SingleFailureChecker( - const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr) - : results_(results), - type_(type), - substr_(substr) {} +SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const std::string& substr) + : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given @@ -705,61 +748,66 @@ void UnitTestImpl::SetTestPartResultReporterForCurrentThread( per_thread_test_part_result_reporter_.set(reporter); } -// Gets the number of successful test cases. -int UnitTestImpl::successful_test_case_count() const { - return CountIf(test_cases_, TestCasePassed); +// Gets the number of successful test suites. +int UnitTestImpl::successful_test_suite_count() const { + return CountIf(test_suites_, TestSuitePassed); } -// Gets the number of failed test cases. -int UnitTestImpl::failed_test_case_count() const { - return CountIf(test_cases_, TestCaseFailed); +// Gets the number of failed test suites. +int UnitTestImpl::failed_test_suite_count() const { + return CountIf(test_suites_, TestSuiteFailed); } -// Gets the number of all test cases. -int UnitTestImpl::total_test_case_count() const { - return static_cast(test_cases_.size()); +// Gets the number of all test suites. +int UnitTestImpl::total_test_suite_count() const { + return static_cast(test_suites_.size()); } -// Gets the number of all test cases that contain at least one test +// Gets the number of all test suites that contain at least one test // that should run. -int UnitTestImpl::test_case_to_run_count() const { - return CountIf(test_cases_, ShouldRunTestCase); +int UnitTestImpl::test_suite_to_run_count() const { + return CountIf(test_suites_, ShouldRunTestSuite); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::successful_test_count); +} + +// Gets the number of skipped tests. +int UnitTestImpl::skipped_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::skipped_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::failed_test_count); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { - return SumOverTestCaseList(test_cases_, - &TestCase::reportable_disabled_test_count); + return SumOverTestSuiteList(test_suites_, + &TestSuite::reportable_disabled_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::disabled_test_count); } // Gets the number of tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::test_to_run_count); } // Returns the current OS stack trace as an std::string. @@ -773,8 +821,12 @@ int UnitTestImpl::test_to_run_count() const { // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { - (void)skip_count; - return ""; + return os_stack_trace_getter()->CurrentStackTrace( + static_cast(GTEST_FLAG(stack_trace_depth)), + skip_count + 1 + // Skips the user-specified number of frames plus this function + // itself. + ); // NOLINT } // Returns the current time in milliseconds. @@ -789,8 +841,6 @@ TimeInMillis GetTimeInMillis() { SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; - // TODO(kenton@google.com): Shouldn't this just use - // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; @@ -803,26 +853,16 @@ TimeInMillis GetTimeInMillis() { #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; -# ifdef _MSC_VER - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. - // TODO(kenton@google.com): Use GetTickCount()? Or use - // SystemTimeToFileTime() -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996. - _ftime64(&now); -# pragma warning(pop) // Restores the warning state. -# else - + GTEST_DISABLE_MSC_DEPRECATED_PUSH_() _ftime64(&now); - -# endif // _MSC_VER + GTEST_DISABLE_MSC_DEPRECATED_POP_() return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else # error "Don't know how to get the current time on your system." @@ -839,11 +879,10 @@ TimeInMillis GetTimeInMillis() { // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { - if (!ansi) return NULL; + if (!ansi) return nullptr; const int length = strlen(ansi); const int unicode_length = - MultiByteToWideChar(CP_ACP, 0, ansi, length, - NULL, 0); + MultiByteToWideChar(CP_ACP, 0, ansi, length, nullptr, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); @@ -856,33 +895,33 @@ LPCWSTR String::AnsiToUtf16(const char* ansi) { // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { - if (!utf16_str) return NULL; - const int ansi_length = - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - NULL, 0, NULL, NULL); + if (!utf16_str) return nullptr; + const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, nullptr, + 0, nullptr, nullptr); char* ansi = new char[ansi_length + 1]; - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - ansi, ansi_length, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, nullptr, + nullptr); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE -// Compares two C strings. Returns true iff they have the same content. +// Compares two C strings. Returns true if and only if they have the same +// content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { - if ( lhs == NULL ) return rhs == NULL; + if (lhs == nullptr) return rhs == nullptr; - if ( rhs == NULL ) return false; + if (rhs == nullptr) return false; return strcmp(lhs, rhs) == 0; } -#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +#if GTEST_HAS_STD_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. @@ -900,7 +939,24 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, } } -#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +#endif // GTEST_HAS_STD_WSTRING + +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} } // namespace internal @@ -933,15 +989,6 @@ Message& Message::operator <<(const ::std::wstring& wstr) { } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_GLOBAL_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_GLOBAL_WSTRING - // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { @@ -952,16 +999,21 @@ std::string Message::GetString() const { // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), - message_(other.message_.get() != NULL ? - new ::std::string(*other.message_) : - static_cast< ::std::string*>(NULL)) { + message_(other.message_.get() != nullptr + ? new ::std::string(*other.message_) + : static_cast< ::std::string*>(nullptr)) {} + +// Swaps two AssertionResults. +void AssertionResult::swap(AssertionResult& other) { + using std::swap; + swap(success_, other.success_); + swap(message_, other.message_); } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); - if (message_.get() != NULL) - negation << *message_; + if (message_.get() != nullptr) negation << *message_; return negation; } @@ -983,6 +1035,277 @@ AssertionResult AssertionFailure(const Message& message) { namespace internal { +namespace edit_distance { +std::vector CalculateOptimalEdits(const std::vector& left, + const std::vector& right) { + std::vector > costs( + left.size() + 1, std::vector(right.size() + 1)); + std::vector > best_move( + left.size() + 1, std::vector(right.size() + 1)); + + // Populate for empty right. + for (size_t l_i = 0; l_i < costs.size(); ++l_i) { + costs[l_i][0] = static_cast(l_i); + best_move[l_i][0] = kRemove; + } + // Populate for empty left. + for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { + costs[0][r_i] = static_cast(r_i); + best_move[0][r_i] = kAdd; + } + + for (size_t l_i = 0; l_i < left.size(); ++l_i) { + for (size_t r_i = 0; r_i < right.size(); ++r_i) { + if (left[l_i] == right[r_i]) { + // Found a match. Consume it. + costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; + best_move[l_i + 1][r_i + 1] = kMatch; + continue; + } + + const double add = costs[l_i + 1][r_i]; + const double remove = costs[l_i][r_i + 1]; + const double replace = costs[l_i][r_i]; + if (add < remove && add < replace) { + costs[l_i + 1][r_i + 1] = add + 1; + best_move[l_i + 1][r_i + 1] = kAdd; + } else if (remove < add && remove < replace) { + costs[l_i + 1][r_i + 1] = remove + 1; + best_move[l_i + 1][r_i + 1] = kRemove; + } else { + // We make replace a little more expensive than add/remove to lower + // their priority. + costs[l_i + 1][r_i + 1] = replace + 1.00001; + best_move[l_i + 1][r_i + 1] = kReplace; + } + } + } + + // Reconstruct the best path. We do it in reverse order. + std::vector best_path; + for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { + EditType move = best_move[l_i][r_i]; + best_path.push_back(move); + l_i -= move != kAdd; + r_i -= move != kRemove; + } + std::reverse(best_path.begin(), best_path.end()); + return best_path; +} + +namespace { + +// Helper class to convert string into ids with deduplication. +class InternalStrings { + public: + size_t GetId(const std::string& str) { + IdMap::iterator it = ids_.find(str); + if (it != ids_.end()) return it->second; + size_t id = ids_.size(); + return ids_[str] = id; + } + + private: + typedef std::map IdMap; + IdMap ids_; +}; + +} // namespace + +std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right) { + std::vector left_ids, right_ids; + { + InternalStrings intern_table; + for (size_t i = 0; i < left.size(); ++i) { + left_ids.push_back(intern_table.GetId(left[i])); + } + for (size_t i = 0; i < right.size(); ++i) { + right_ids.push_back(intern_table.GetId(right[i])); + } + } + return CalculateOptimalEdits(left_ids, right_ids); +} + +namespace { + +// Helper class that holds the state for one hunk and prints it out to the +// stream. +// It reorders adds/removes when possible to group all removes before all +// adds. It also adds the hunk header before printint into the stream. +class Hunk { + public: + Hunk(size_t left_start, size_t right_start) + : left_start_(left_start), + right_start_(right_start), + adds_(), + removes_(), + common_() {} + + void PushLine(char edit, const char* line) { + switch (edit) { + case ' ': + ++common_; + FlushEdits(); + hunk_.push_back(std::make_pair(' ', line)); + break; + case '-': + ++removes_; + hunk_removes_.push_back(std::make_pair('-', line)); + break; + case '+': + ++adds_; + hunk_adds_.push_back(std::make_pair('+', line)); + break; + } + } + + void PrintTo(std::ostream* os) { + PrintHeader(os); + FlushEdits(); + for (std::list >::const_iterator it = + hunk_.begin(); + it != hunk_.end(); ++it) { + *os << it->first << it->second << "\n"; + } + } + + bool has_edits() const { return adds_ || removes_; } + + private: + void FlushEdits() { + hunk_.splice(hunk_.end(), hunk_removes_); + hunk_.splice(hunk_.end(), hunk_adds_); + } + + // Print a unified diff header for one hunk. + // The format is + // "@@ -, +, @@" + // where the left/right parts are omitted if unnecessary. + void PrintHeader(std::ostream* ss) const { + *ss << "@@ "; + if (removes_) { + *ss << "-" << left_start_ << "," << (removes_ + common_); + } + if (removes_ && adds_) { + *ss << " "; + } + if (adds_) { + *ss << "+" << right_start_ << "," << (adds_ + common_); + } + *ss << " @@\n"; + } + + size_t left_start_, right_start_; + size_t adds_, removes_, common_; + std::list > hunk_, hunk_adds_, hunk_removes_; +}; + +} // namespace + +// Create a list of diff hunks in Unified diff format. +// Each hunk has a header generated by PrintHeader above plus a body with +// lines prefixed with ' ' for no change, '-' for deletion and '+' for +// addition. +// 'context' represents the desired unchanged prefix/suffix around the diff. +// If two hunks are close enough that their contexts overlap, then they are +// joined into one hunk. +std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context) { + const std::vector edits = CalculateOptimalEdits(left, right); + + size_t l_i = 0, r_i = 0, edit_i = 0; + std::stringstream ss; + while (edit_i < edits.size()) { + // Find first edit. + while (edit_i < edits.size() && edits[edit_i] == kMatch) { + ++l_i; + ++r_i; + ++edit_i; + } + + // Find the first line to include in the hunk. + const size_t prefix_context = std::min(l_i, context); + Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); + for (size_t i = prefix_context; i > 0; --i) { + hunk.PushLine(' ', left[l_i - i].c_str()); + } + + // Iterate the edits until we found enough suffix for the hunk or the input + // is over. + size_t n_suffix = 0; + for (; edit_i < edits.size(); ++edit_i) { + if (n_suffix >= context) { + // Continue only if the next hunk is very close. + auto it = edits.begin() + static_cast(edit_i); + while (it != edits.end() && *it == kMatch) ++it; + if (it == edits.end() || + static_cast(it - edits.begin()) - edit_i >= context) { + // There is no next edit or it is too far away. + break; + } + } + + EditType edit = edits[edit_i]; + // Reset count when a non match is found. + n_suffix = edit == kMatch ? n_suffix + 1 : 0; + + if (edit == kMatch || edit == kRemove || edit == kReplace) { + hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); + } + if (edit == kAdd || edit == kReplace) { + hunk.PushLine('+', right[r_i].c_str()); + } + + // Advance indices, depending on edit type. + l_i += edit != kAdd; + r_i += edit != kRemove; + } + + if (!hunk.has_edits()) { + // We are done. We don't want this hunk. + break; + } + + hunk.PrintTo(&ss); + } + return ss.str(); +} + +} // namespace edit_distance + +namespace { + +// The string representation of the values received in EqFailure() are already +// escaped. Split them on escaped '\n' boundaries. Leave all other escaped +// characters the same. +std::vector SplitEscapedString(const std::string& str) { + std::vector lines; + size_t start = 0, end = str.size(); + if (end > 2 && str[0] == '"' && str[end - 1] == '"') { + ++start; + --end; + } + bool escaped = false; + for (size_t i = start; i + 1 < end; ++i) { + if (escaped) { + escaped = false; + if (str[i] == 'n') { + lines.push_back(str.substr(start, i - start - 1)); + start = i + 1; + } + } else { + escaped = str[i] == '\\'; + } + } + lines.push_back(str.substr(start, end - start)); + return lines; +} + +} // namespace + // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // @@ -990,31 +1313,43 @@ namespace internal { // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" +// lhs_expression: "foo" +// rhs_expression: "bar" +// lhs_value: "5" +// rhs_value: "6" // -// The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// The ignoring_case parameter is true if and only if the assertion is a +// *_STRCASEEQ*. When it's true, the string "Ignoring case" will // be inserted into the message. -AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const std::string& expected_value, - const std::string& actual_value, +AssertionResult EqFailure(const char* lhs_expression, + const char* rhs_expression, + const std::string& lhs_value, + const std::string& rhs_value, bool ignoring_case) { Message msg; - msg << "Value of: " << actual_expression; - if (actual_value != actual_expression) { - msg << "\n Actual: " << actual_value; + msg << "Expected equality of these values:"; + msg << "\n " << lhs_expression; + if (lhs_value != lhs_expression) { + msg << "\n Which is: " << lhs_value; + } + msg << "\n " << rhs_expression; + if (rhs_value != rhs_expression) { + msg << "\n Which is: " << rhs_value; } - msg << "\nExpected: " << expected_expression; if (ignoring_case) { - msg << " (ignoring case)"; + msg << "\nIgnoring case"; } - if (expected_value != expected_expression) { - msg << "\nWhich is: " << expected_value; + + if (!lhs_value.empty() && !rhs_value.empty()) { + const std::vector lhs_lines = + SplitEscapedString(lhs_value); + const std::vector rhs_lines = + SplitEscapedString(rhs_value); + if (lhs_lines.size() > 1 || rhs_lines.size() > 1) { + msg << "\nWith diff:\n" + << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines); + } } return AssertionFailure() << msg; @@ -1046,8 +1381,6 @@ AssertionResult DoubleNearPredFormat(const char* expr1, const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); - // TODO(wan): do not print the value of an expression if it's - // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" @@ -1112,18 +1445,18 @@ namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - if (expected == actual) { +AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs) { + if (lhs == rhs) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), + return EqFailure(lhs_expression, + rhs_expression, + FormatForComparisonFailureMessage(lhs, rhs), + FormatForComparisonFailureMessage(rhs, lhs), false); } @@ -1162,34 +1495,34 @@ GTEST_IMPL_CMP_HELPER_(GT, > ) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CStringEquals(expected, actual)) { +AssertionResult CmpHelperSTREQ(const char* lhs_expression, + const char* rhs_expression, + const char* lhs, + const char* rhs) { + if (String::CStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. -AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CaseInsensitiveCStringEquals(expected, actual)) { +AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression, + const char* rhs_expression, + const char* lhs, + const char* rhs) { + if (String::CaseInsensitiveCStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), true); } @@ -1228,22 +1561,20 @@ namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). -// This group of overloaded functions return true iff needle is a -// substring of haystack. NULL is considered a substring of itself -// only. +// This group of overloaded functions return true if and only if needle +// is a substring of haystack. NULL is considered a substring of +// itself only. bool IsSubstringPred(const char* needle, const char* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; + if (needle == nullptr || haystack == nullptr) return needle == haystack; - return strstr(haystack, needle) != NULL; + return strstr(haystack, needle) != nullptr; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; + if (needle == nullptr || haystack == nullptr) return needle == haystack; - return wcsstr(haystack, needle) != NULL; + return wcsstr(haystack, needle) != nullptr; } // StringType here can be either ::std::string or ::std::wstring. @@ -1341,7 +1672,7 @@ namespace { AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT -# if GTEST_OS_WINDOWS_MOBILE +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; @@ -1357,12 +1688,12 @@ AssertionResult HRESULTFailureHelper(const char* expr, // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, - 0, // no source, we're asking system - hr, // the error - 0, // no line width restrictions + 0, // no source, we're asking system + static_cast(hr), // the error + 0, // no line width restrictions error_text, // output buffer - kBufSize, // buf size - NULL); // no arguments for inserts + kBufSize, // buf size + nullptr); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { @@ -1398,7 +1729,7 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT // Utility functions for encoding Unicode text (wide strings) in // UTF-8. -// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding @@ -1436,7 +1767,7 @@ inline UInt32 ChopLowBits(UInt32* bits, int n) { // to "(Invalid Unicode 0xXXXXXXXX)". std::string CodePointToUtf8(UInt32 code_point) { if (code_point > kMaxCodePoint4) { - return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; + return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. @@ -1462,9 +1793,9 @@ std::string CodePointToUtf8(UInt32 code_point) { return str; } -// The following two functions only make sense if the the system +// The following two functions only make sense if the system // uses UTF-16 for wide string encoding. All supported systems -// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. +// with 16 bit wchar_t (Windows, Cygwin) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point @@ -1477,17 +1808,20 @@ inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { + const auto first_u = static_cast(first); + const auto second_u = static_cast(second); const UInt32 mask = (1 << 10) - 1; - return (sizeof(wchar_t) == 2) ? - (((first & mask) << 10) | (second & mask)) + 0x10000 : - // This function should not be called when the condition is - // false, but we provide a sensible default in case it is. - static_cast(first); + return (sizeof(wchar_t) == 2) + ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000 + : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + first_u; } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number @@ -1524,38 +1858,38 @@ std::string WideStringToUtf8(const wchar_t* str, int num_chars) { // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". std::string String::ShowWideCString(const wchar_t * wide_c_str) { - if (wide_c_str == NULL) return "(null)"; + if (wide_c_str == nullptr) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } -// Compares two wide C strings. Returns true iff they have the same -// content. +// Compares two wide C strings. Returns true if and only if they have the +// same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { - if (lhs == NULL) return rhs == NULL; + if (lhs == nullptr) return rhs == nullptr; - if (rhs == NULL) return false; + if (rhs == nullptr) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual) { - if (String::WideCStringEquals(expected, actual)) { +AssertionResult CmpHelperSTREQ(const char* lhs_expression, + const char* rhs_expression, + const wchar_t* lhs, + const wchar_t* rhs) { + if (String::WideCStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), false); } @@ -1574,37 +1908,35 @@ AssertionResult CmpHelperSTRNE(const char* s1_expression, << " vs " << PrintToString(s2); } -// Compares two C strings, ignoring case. Returns true iff they have +// Compares two C strings, ignoring case. Returns true if and only if they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { - if (lhs == NULL) - return rhs == NULL; - if (rhs == NULL) - return false; + if (lhs == nullptr) return rhs == nullptr; + if (rhs == nullptr) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. +// Compares two wide C strings, ignoring case. Returns true if and only if they +// have the same content. +// +// Unlike wcscasecmp(), this function can handle NULL argument(s). +// A NULL C string is considered different to any non-NULL wide C string, +// including the empty string. +// NB: The implementations on different platforms slightly differ. +// On windows, this method uses _wcsicmp which compares according to LC_CTYPE +// environment variable. On GNU platform this method uses wcscasecmp +// which compares according to LC_CTYPE category of the current locale. +// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the +// current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { - if (lhs == NULL) return rhs == NULL; + if (lhs == nullptr) return rhs == nullptr; - if (rhs == NULL) return false; + if (rhs == nullptr) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; @@ -1615,14 +1947,14 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, // Other unknown OSes may not define it either. wint_t left, right; do { - left = towlower(*lhs++); - right = towlower(*rhs++); + left = towlower(static_cast(*lhs++)); + right = towlower(static_cast(*rhs++)); } while (left && left == right); return left == right; #endif // OS selector } -// Returns true iff str ends with the given suffix, ignoring case. +// Returns true if and only if str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. bool String::EndsWithCaseInsensitive( const std::string& str, const std::string& suffix) { @@ -1641,12 +1973,17 @@ std::string String::FormatIntWidth2(int value) { } // Formats an int value as "%X". -std::string String::FormatHexInt(int value) { +std::string String::FormatHexUInt32(UInt32 value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } +// Formats an int value as "%X". +std::string String::FormatHexInt(int value) { + return FormatHexUInt32(static_cast(value)); +} + // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; @@ -1663,7 +2000,7 @@ std::string StringStreamToString(::std::stringstream* ss) { const char* const end = start + str.length(); std::string result; - result.reserve(2 * (end - start)); + result.reserve(static_cast(2 * (end - start))); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; @@ -1693,9 +2030,7 @@ std::string AppendUserMessage(const std::string& gtest_msg, // Creates an empty TestResult. TestResult::TestResult() - : death_test_count_(0), - elapsed_time_(0) { -} + : death_test_count_(0), start_timestamp_(0), elapsed_time_(0) {} // D'tor. TestResult::~TestResult() { @@ -1707,7 +2042,7 @@ TestResult::~TestResult() { const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); - return test_part_results_.at(i); + return test_part_results_.at(static_cast(i)); } // Returns the i-th test property. i can range from 0 to @@ -1716,7 +2051,7 @@ const TestPartResult& TestResult::GetTestPartResult(int i) const { const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); - return test_properties_.at(i); + return test_properties_.at(static_cast(i)); } // Clears the test part results. @@ -1764,23 +2099,18 @@ static const char* const kReservedTestSuitesAttributes[] = { // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { - "disabled", - "errors", - "failures", - "name", - "tests", - "time" -}; + "disabled", "errors", "failures", "name", "tests", "time", "timestamp"}; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { - "classname", - "name", - "status", - "time", - "type_param", - "value_param" -}; + "classname", "name", "status", "time", "type_param", + "value_param", "file", "line"}; + +// Use a slightly different set for allowed output to ensure existing tests can +// still RecordProperty("result") or "RecordProperty(timestamp") +static const char* const kReservedOutputTestCaseAttributes[] = { + "classname", "name", "status", "time", "type_param", + "value_param", "file", "line", "result", "timestamp"}; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { @@ -1802,6 +2132,22 @@ static std::vector GetReservedAttributesForElement( return std::vector(); } +// TODO(jdesprez): Merge the two getReserved attributes once skip is improved +static std::vector GetReservedOutputAttributesForElement( + const std::string& xml_element) { + if (xml_element == "testsuites") { + return ArrayAsVector(kReservedTestSuitesAttributes); + } else if (xml_element == "testsuite") { + return ArrayAsVector(kReservedTestSuiteAttributes); + } else if (xml_element == "testcase") { + return ArrayAsVector(kReservedOutputTestCaseAttributes); + } else { + GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; + } + // This code is unreachable but some compilers may not realizes that. + return std::vector(); +} + static std::string FormatWordList(const std::vector& words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { @@ -1816,8 +2162,9 @@ static std::string FormatWordList(const std::vector& words) { return word_list.GetString(); } -bool ValidateTestPropertyName(const std::string& property_name, - const std::vector& reserved_names) { +static bool ValidateTestPropertyName( + const std::string& property_name, + const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name @@ -1844,7 +2191,17 @@ void TestResult::Clear() { elapsed_time_ = 0; } -// Returns true iff the test failed. +// Returns true off the test part was skipped. +static bool TestPartSkipped(const TestPartResult& result) { + return result.skipped(); +} + +// Returns true if and only if the test was skipped. +bool TestResult::Skipped() const { + return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0; +} + +// Returns true if and only if the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) @@ -1853,22 +2210,22 @@ bool TestResult::Failed() const { return false; } -// Returns true iff the test part fatally failed. +// Returns true if and only if the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } -// Returns true iff the test fatally failed. +// Returns true if and only if the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } -// Returns true iff the test part non-fatally failed. +// Returns true if and only if the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } -// Returns true iff the test has a non-fatal failure. +// Returns true if and only if the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } @@ -1888,14 +2245,15 @@ int TestResult::test_property_count() const { // Creates a Test object. -// The c'tor saves the values of all Google Test flags. +// The c'tor saves the states of all flags. Test::Test() - : gtest_flag_saver_(new internal::GTestFlagSaver) { + : gtest_flag_saver_(new GTEST_FLAG_SAVER_) { } -// The d'tor restores the values of all Google Test flags. +// The d'tor restores the states of all flags. The actual work is +// done by the d'tor of the gtest_flag_saver_ field, and thus not +// visible here. Test::~Test() { - delete gtest_flag_saver_; } // Sets up the test fixture. @@ -1930,25 +2288,25 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, - NULL, // No info about the source file where the exception occurred. - -1, // We have no info on which line caused the exception. + nullptr, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. message, - ""); // No stack trace, either. + ""); // No stack trace, either. } } // namespace internal -// Google Test requires all tests in the same test case to use the same test +// Google Test requires all tests in the same test suite to use the same test // fixture class. This function checks if the current test has the -// same fixture class as the first test in the current test case. If +// same fixture class as the first test in the current test suite. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - const TestCase* const test_case = impl->current_test_case(); + const TestSuite* const test_suite = impl->current_test_suite(); - // Info about the first test in the current test case. - const TestInfo* const first_test_info = test_case->test_info_list()[0]; + // Info about the first test in the current test suite. + const TestInfo* const first_test_info = test_suite->test_info_list()[0]; const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); @@ -1964,8 +2322,8 @@ bool Test::HasSameFixtureClass() { const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { - // The user mixed TEST and TEST_F in this test case - we'll tell - // him/her how to fix it. + // Both TEST and TEST_F appear in same test suite, which is incorrect. + // Tell the user how to fix this. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as @@ -1976,27 +2334,27 @@ bool Test::HasSameFixtureClass() { first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class, so mixing TEST_F and TEST in the same test case is\n" - << "illegal. In test case " << this_test_info->test_case_name() + << "All tests in the same test suite must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test suite is\n" + << "illegal. In test suite " << this_test_info->test_suite_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { - // The user defined two fixture classes with the same name in - // two namespaces - we'll tell him/her how to fix it. + // Two fixture classes with the same name appear in two different + // namespaces, which is not allowed. Tell the user how to fix this. ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " - << this_test_info->test_case_name() << ",\n" - << "you defined test " << first_test_name - << " and test " << this_test_name << "\n" + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " + << this_test_info->test_suite_name() << ",\n" + << "you defined test " << first_test_name << " and test " + << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" - << "of the classes to put the tests into different test cases."; + << "of the classes to put the tests into different test suites."; } return false; } @@ -2029,7 +2387,7 @@ namespace internal { static std::string FormatCxxExceptionMessage(const char* description, const char* location) { Message message; - if (description != NULL) { + if (description != nullptr) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; @@ -2113,6 +2471,8 @@ Result HandleExceptionsInMethodIfSupported( #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const AssertionException&) { // NOLINT + // This failure was reported already. } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing @@ -2125,7 +2485,7 @@ Result HandleExceptionsInMethodIfSupported( } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(NULL, location)); + FormatCxxExceptionMessage(nullptr, location)); } return static_cast(0); #else @@ -2145,8 +2505,9 @@ void Test::Run() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); - // We will run the test only if SetUp() was successful. - if (!HasFatalFailure()) { + // We will run the test only if SetUp() was successful and didn't call + // GTEST_SKIP(). + if (!HasFatalFailure() && !IsSkipped()) { impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "the test body"); @@ -2160,31 +2521,37 @@ void Test::Run() { this, &Test::TearDown, "TearDown()"); } -// Returns true iff the current test has a fatal failure. +// Returns true if and only if the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } -// Returns true iff the current test has a non-fatal failure. +// Returns true if and only if the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } +// Returns true if and only if the current test was skipped. +bool Test::IsSkipped() { + return internal::GetUnitTestImpl()->current_test_result()->Skipped(); +} + // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object. -TestInfo::TestInfo(const std::string& a_test_case_name, - const std::string& a_name, - const char* a_type_param, +TestInfo::TestInfo(const std::string& a_test_suite_name, + const std::string& a_name, const char* a_type_param, const char* a_value_param, + internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) - : test_case_name_(a_test_case_name), + : test_suite_name_(a_test_suite_name), name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - value_param_(a_value_param ? new std::string(a_value_param) : NULL), + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), + value_param_(a_value_param ? new std::string(a_value_param) : nullptr), + location_(a_code_location), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), @@ -2202,53 +2569,48 @@ namespace internal { // // Arguments: // -// test_case_name: name of the test case +// test_suite_name: name of the test suite // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. +// code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory) { + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = - new TestInfo(test_case_name, name, type_param, value_param, - fixture_class_id, factory); + new TestInfo(test_suite_name, name, type_param, value_param, + code_location, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } -#if GTEST_HAS_PARAM_TEST -void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line) { +void ReportInvalidTestSuiteType(const char* test_suite_name, + CodeLocation code_location) { Message errors; errors - << "Attempted redefinition of test case " << test_case_name << ".\n" - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " << test_case_name << ", you tried\n" + << "Attempted redefinition of test suite " << test_suite_name << ".\n" + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " << test_suite_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" - << "test cases."; + << "test suites."; - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors.GetString().c_str()); + GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(), + code_location.line) + << " " << errors.GetString(); } -#endif // GTEST_HAS_PARAM_TEST - } // namespace internal namespace { @@ -2256,7 +2618,7 @@ namespace { // A predicate that checks the test name of a TestInfo against a known // value. // -// This is used for implementation of the TestCase class only. We put +// This is used for implementation of the TestSuite class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // @@ -2269,7 +2631,7 @@ class TestNameIs { explicit TestNameIs(const char* name) : name_(name) {} - // Returns true iff the test name of test_info matches name_. + // Returns true if and only if the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && test_info->name() == name_; } @@ -2283,15 +2645,13 @@ class TestNameIs { namespace internal { // This method expands all parameterized tests registered with macros TEST_P -// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// and INSTANTIATE_TEST_SUITE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { -#if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } -#endif } } // namespace internal @@ -2319,19 +2679,23 @@ void TestInfo::Run() { factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); - // Runs the test only if the test object was created and its - // constructor didn't generate a fatal failure. - if ((test != NULL) && !Test::HasFatalFailure()) { + // Runs the test if the constructor didn't generate a fatal failure or invoke + // GTEST_SKIP(). + // Note that the object will not be null + if (!Test::HasFatalFailure() && !Test::IsSkipped()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } - // Deletes the test object. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - test, &Test::DeleteSelf_, "the test fixture's destructor"); + if (test != nullptr) { + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); + } + result_.set_start_timestamp(start); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. @@ -2339,134 +2703,151 @@ void TestInfo::Run() { // Tells UnitTest to stop associating assertion results to this // test. - impl->set_current_test_info(NULL); + impl->set_current_test_info(nullptr); } -// class TestCase +// class TestSuite -// Gets the number of successful tests in this test case. -int TestCase::successful_test_count() const { +// Gets the number of successful tests in this test suite. +int TestSuite::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } -// Gets the number of failed tests in this test case. -int TestCase::failed_test_count() const { +// Gets the number of successful tests in this test suite. +int TestSuite::skipped_test_count() const { + return CountIf(test_info_list_, TestSkipped); +} + +// Gets the number of failed tests in this test suite. +int TestSuite::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } // Gets the number of disabled tests that will be reported in the XML report. -int TestCase::reportable_disabled_test_count() const { +int TestSuite::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } -// Gets the number of disabled tests in this test case. -int TestCase::disabled_test_count() const { +// Gets the number of disabled tests in this test suite. +int TestSuite::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. -int TestCase::reportable_test_count() const { +int TestSuite::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } -// Get the number of tests in this test case that should run. -int TestCase::test_to_run_count() const { +// Get the number of tests in this test suite that should run. +int TestSuite::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. -int TestCase::total_test_count() const { +int TestSuite::total_test_count() const { return static_cast(test_info_list_.size()); } -// Creates a TestCase with the given name. +// Creates a TestSuite with the given name. // // Arguments: // -// name: name of the test case -// a_type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* a_name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) +// name: name of the test suite +// a_type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite::TestSuite(const char* a_name, const char* a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) : name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), - elapsed_time_(0) { -} + start_timestamp_(0), + elapsed_time_(0) {} -// Destructor of TestCase. -TestCase::~TestCase() { +// Destructor of TestSuite. +TestSuite::~TestSuite() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. -const TestInfo* TestCase::GetTestInfo(int i) const { +const TestInfo* TestSuite::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; + return index < 0 ? nullptr : test_info_list_[static_cast(index)]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. -TestInfo* TestCase::GetMutableTestInfo(int i) { +TestInfo* TestSuite::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; + return index < 0 ? nullptr : test_info_list_[static_cast(index)]; } -// Adds a test to this test case. Will delete the test upon -// destruction of the TestCase object. -void TestCase::AddTestInfo(TestInfo * test_info) { +// Adds a test to this test suite. Will delete the test upon +// destruction of the TestSuite object. +void TestSuite::AddTestInfo(TestInfo* test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } -// Runs every test in this TestCase. -void TestCase::Run() { +// Runs every test in this TestSuite. +void TestSuite::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_case(this); + impl->set_current_test_suite(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + // Call both legacy and the new API + repeater->OnTestSuiteStart(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseStart(*this); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()"); - const internal::TimeInMillis start = internal::GetTimeInMillis(); + start_timestamp_ = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } - elapsed_time_ = internal::GetTimeInMillis() - start; + elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()"); + // Call both legacy and the new API + repeater->OnTestSuiteEnd(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseEnd(*this); - impl->set_current_test_case(NULL); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + + impl->set_current_test_suite(nullptr); } -// Clears the results of all tests in this test case. -void TestCase::ClearResult() { +// Clears the results of all tests in this test suite. +void TestSuite::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } -// Shuffles the tests in this test case. -void TestCase::ShuffleTests(internal::Random* random) { +// Shuffles the tests in this test suite. +void TestSuite::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. -void TestCase::UnshuffleTests() { +void TestSuite::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } @@ -2489,9 +2870,9 @@ static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } -// Formats the count of test cases. -static std::string FormatTestCaseCount(int test_case_count) { - return FormatCountableNoun(test_case_count, "test case", "test cases"); +// Formats the count of test suites. +static std::string FormatTestSuiteCount(int test_suite_count) { + return FormatCountableNoun(test_suite_count, "test suite", "test suites"); } // Converts a TestPartResult::Type enum to human-friendly string @@ -2500,6 +2881,8 @@ static std::string FormatTestCaseCount(int test_case_count) { // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { + case TestPartResult::kSkip: + return "Skipped"; case TestPartResult::kSuccess: return "Success"; @@ -2547,18 +2930,11 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) { } // class PrettyUnitTestResultPrinter - -enum GTestColor { - COLOR_DEFAULT, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW -}; - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW // Returns the character attribute for the given color. -WORD GetColorAttribute(GTestColor color) { +static WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; @@ -2567,27 +2943,59 @@ WORD GetColorAttribute(GTestColor color) { } } +static int GetBitOffset(WORD color_mask) { + if (color_mask == 0) return 0; + + int bitOffset = 0; + while ((color_mask & 1) == 0) { + color_mask >>= 1; + ++bitOffset; + } + return bitOffset; +} + +static WORD GetNewColor(GTestColor color, WORD old_color_attrs) { + // Let's reuse the BG + static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY; + static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED | FOREGROUND_INTENSITY; + const WORD existing_bg = old_color_attrs & background_mask; + + WORD new_color = + GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY; + static const int bg_bitOffset = GetBitOffset(background_mask); + static const int fg_bitOffset = GetBitOffset(foreground_mask); + + if (((new_color & background_mask) >> bg_bitOffset) == + ((new_color & foreground_mask) >> fg_bitOffset)) { + new_color ^= FOREGROUND_INTENSITY; // invert intensity + } + return new_color; +} + #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. -const char* GetAnsiColorCode(GTestColor color) { +static const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; - default: return NULL; - }; + default: + return nullptr; + } } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE -// Returns true iff Google Test should use colors in the output. +// Returns true if and only if Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; @@ -2600,6 +3008,10 @@ bool ShouldUseColor(bool stdout_is_tty) { String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || String::CStringEquals(term, "screen-256color") || + String::CStringEquals(term, "tmux") || + String::CStringEquals(term, "tmux-256color") || + String::CStringEquals(term, "rxvt-unicode") || + String::CStringEquals(term, "rxvt-unicode-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; @@ -2623,14 +3035,14 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS - const bool use_color = false; +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS || GTEST_OS_IOS || \ + GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM) + const bool use_color = AlwaysFalse(); #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); -#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - // The '!= 0' comparison is necessary to satisfy MSVC 7.1. +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS if (!use_color) { vprintf(fmt, args); @@ -2638,20 +3050,22 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; + const WORD new_color = GetNewColor(color, old_color_attrs); // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); - SetConsoleTextAttribute(stdout_handle, - GetColorAttribute(color) | FOREGROUND_INTENSITY); + SetConsoleTextAttribute(stdout_handle, new_color); + vprintf(fmt, args); fflush(stdout); @@ -2665,23 +3079,22 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_end(args); } -// Text printed in Google Test's text output and --gunit_list_tests +// Text printed in Google Test's text output and --gtest_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; -void PrintFullTestCommentIfPresent(const TestInfo& test_info) { +static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); - if (type_param != NULL || value_param != NULL) { + if (type_param != nullptr || value_param != nullptr) { printf(", where "); - if (type_param != NULL) { + if (type_param != nullptr) { printf("%s = %s", kTypeParamLabel, type_param); - if (value_param != NULL) - printf(" and "); + if (value_param != nullptr) printf(" and "); } - if (value_param != NULL) { + if (value_param != nullptr) { printf("%s = %s", kValueParamLabel, value_param); } } @@ -2693,27 +3106,39 @@ void PrintFullTestCommentIfPresent(const TestInfo& test_info) { class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} - static void PrintTestName(const char * test_case, const char * test) { - printf("%s.%s", test_case, test); + static void PrintTestName(const char* test_suite, const char* test) { + printf("%s.%s", test_suite, test); } // The following methods override what's in the TestEventListener class. - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& test_case) override; +#else + void OnTestSuiteStart(const TestSuite& test_suite) override; +#endif // OnTestCaseStart + + void OnTestStart(const TestInfo& test_info) override; + + void OnTestPartResult(const TestPartResult& result) override; + void OnTestEnd(const TestInfo& test_info) override; +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& test_case) override; +#else + void OnTestSuiteEnd(const TestSuite& test_suite) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} private: static void PrintFailedTests(const UnitTest& unit_test); + static void PrintSkippedTests(const UnitTest& unit_test); }; // Fired before each iteration of tests starts. @@ -2748,7 +3173,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationStart( ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); fflush(stdout); } @@ -2759,22 +3184,38 @@ void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( fflush(stdout); } +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); - if (test_case.type_param() == NULL) { + if (test_case.type_param() == nullptr) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } +#else +void PrettyUnitTestResultPrinter::OnTestSuiteStart( + const TestSuite& test_suite) { + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_suite.name()); + if (test_suite.type_param() == nullptr) { + printf("\n"); + } else { + printf(", where %s = %s\n", kTypeParamLabel, test_suite.type_param()); + } + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_info.test_case_name(), test_info.name()); + PrintTestName(test_info.test_suite_name(), test_info.name()); printf("\n"); fflush(stdout); } @@ -2782,22 +3223,29 @@ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { - // If the test part succeeded, we don't need to do anything. - if (result.type() == TestPartResult::kSuccess) - return; - - // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(result); - fflush(stdout); + switch (result.type()) { + // If the test part succeeded, or was skipped, + // we don't need to do anything. + case TestPartResult::kSkip: + case TestPartResult::kSuccess: + return; + default: + // Print failure message from the assertion + // (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); + } } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else if (test_info.result()->Skipped()) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } - PrintTestName(test_info.test_case_name(), test_info.name()); + PrintTestName(test_info.test_suite_name(), test_info.name()); if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); @@ -2810,17 +3258,29 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { fflush(stdout); } +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s (%s ms total)\n\n", - counts.c_str(), test_case.name(), + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } +#else +void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) { + if (!GTEST_FLAG(print_time)) return; + + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(), + internal::StreamableToString(test_suite.elapsed_time()).c_str()); + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { @@ -2836,30 +3296,54 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { return; } - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - const TestCase& test_case = *unit_test.GetTestCase(i); - if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite& test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.failed_test_count() == 0)) { continue; } - for (int j = 0; j < test_case.total_test_count(); ++j) { - const TestInfo& test_info = *test_case.GetTestInfo(j); - if (!test_info.should_run() || test_info.result()->Passed()) { + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo& test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Failed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s", test_case.name(), test_info.name()); + printf("%s.%s", test_suite.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } } -void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { +// Internal helper for printing the list of skipped tests. +void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) { + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite& test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.skipped_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo& test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Skipped()) { + continue; + } + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s.%s", test_suite.name(), test_info.name()); + printf("\n"); + } + } +} + +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); @@ -2868,6 +3352,13 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count > 0) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str()); + PrintSkippedTests(unit_test); + } + int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); @@ -2900,7 +3391,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} - virtual ~TestEventRepeater(); + ~TestEventRepeater() override; void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); @@ -2909,19 +3400,27 @@ class TestEventRepeater : public TestEventListener { bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& unit_test); + void OnTestProgramStart(const UnitTest& unit_test) override; + void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestSuite& parameter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteStart(const TestSuite& parameter) override; + void OnTestStart(const TestInfo& test_info) override; + void OnTestPartResult(const TestPartResult& result) override; + void OnTestEnd(const TestInfo& test_info) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& parameter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteEnd(const TestSuite& parameter) override; + void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) override; + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest& unit_test) override; private: // Controls whether events will be forwarded to listeners_. Set to false @@ -2941,16 +3440,15 @@ void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } -// TODO(vladl@google.com): Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { - listeners_.erase(listeners_.begin() + i); + listeners_.erase(listeners_.begin() + static_cast(i)); return listener; } } - return NULL; + return nullptr; } // Since most methods are very similar, use macros to reduce boilerplate. @@ -2965,25 +3463,33 @@ void TestEventRepeater::Name(const Type& parameter) { \ } // This defines a member that forwards the call to all listeners in reverse // order. -#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ + void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = listeners_.size(); i != 0; i--) { \ + listeners_[i - 1]->Name(parameter); \ + } \ + } \ + } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) -GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestSuiteEnd, TestSuite) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ @@ -3001,8 +3507,8 @@ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { - listeners_[i]->OnTestIterationEnd(unit_test, iteration); + for (size_t i = listeners_.size(); i > 0; i--) { + listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration); } } } @@ -3014,7 +3520,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void ListTestsMatchingFilter(const std::vector& test_suites); + + // Prints an XML summary of all unit tests. + static void PrintXmlTestsList(std::ostream* stream, + const std::vector& test_suites); private: // Is c a whitespace character that is normalized to a space character @@ -3059,12 +3570,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, + const char* test_suite_name, const TestInfo& test_info); - // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(::std::ostream* stream, - const TestCase& test_case); + // Prints an XML representation of a TestSuite object + static void PrintXmlTestSuite(::std::ostream* stream, + const TestSuite& test_suite); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(::std::ostream* stream, @@ -3076,6 +3587,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); + // Streams an XML representation of the test properties of a TestResult + // object. + static void OutputXmlTestProperties(std::ostream* stream, + const TestResult& result); + // The output file. const std::string output_file_; @@ -3085,46 +3601,30 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { - if (output_file_.c_str() == NULL || output_file_.empty()) { - fprintf(stderr, "XML output file may not be null\n"); - fflush(stderr); - exit(EXIT_FAILURE); + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "XML output file may not be null"; } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // TODO(wan): report the reason of the failure. - // - // We don't do it for now as: - // - // 1. There is no urgent need for it. - // 2. It's a bit involved to make the errno variable thread-safe on - // all three operating systems (Linux, Windows, and Mac OS). - // 3. To interpret the meaning of errno in a thread-safe way, - // we need the strerror_r() function, which is not available on - // Windows. - fprintf(stderr, - "Unable to open file \"%s\"\n", - output_file_.c_str()); - fflush(stderr); - exit(EXIT_FAILURE); - } + FILE* xmlout = OpenFileForWriting(output_file_); std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } +void XmlUnitTestResultPrinter::ListTestsMatchingFilter( + const std::vector& test_suites) { + FILE* xmlout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintXmlTestsList(&stream, test_suites); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); + fclose(xmlout); +} + // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character @@ -3135,8 +3635,6 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. -// TODO(wan): It might be nice to have a minimally invasive, human-readable -// escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { Message m; @@ -3196,11 +3694,12 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // The following routines generate an XML representation of a UnitTest // object. +// GOOGLETEST_CM0009 DO NOT DELETE // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object -// <-- corresponds to a TestCase object +// <-- corresponds to a TestSuite object // <-- corresponds to a TestInfo object // ... // ... @@ -3213,34 +3712,38 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; - ss << ms/1000.0; + ss << (static_cast(ms) * 1e-3); return ss.str(); } -// Converts the given epoch time in milliseconds to a date string in the ISO -// 8601 format, without the timezone information. -std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { - // Using non-reentrant version as localtime_r is not portable. - time_t seconds = static_cast(ms / 1000); -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996 - // (function or variable may be unsafe). - const struct tm* const time_struct = localtime(&seconds); // NOLINT -# pragma warning(pop) // Restores the warning state again. +static bool PortableLocaltime(time_t seconds, struct tm* out) { +#if defined(_MSC_VER) + return localtime_s(out, &seconds) == 0; +#elif defined(__MINGW32__) || defined(__MINGW64__) + // MINGW provides neither localtime_r nor localtime_s, but uses + // Windows' localtime(), which has a thread-local tm buffer. + struct tm* tm_ptr = localtime(&seconds); // NOLINT + if (tm_ptr == nullptr) return false; + *out = *tm_ptr; + return true; #else - const struct tm* const time_struct = localtime(&seconds); // NOLINT + return localtime_r(&seconds, out) != nullptr; #endif - if (time_struct == NULL) - return ""; // Invalid ms value +} +// Converts the given epoch time in milliseconds to a date string in the ISO +// 8601 format, without the timezone information. +std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { + struct tm time_struct; + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; // YYYY-MM-DDThh:mm:ss - return StreamableToString(time_struct->tm_year + 1900) + "-" + - String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + - String::FormatIntWidth2(time_struct->tm_mday) + "T" + - String::FormatIntWidth2(time_struct->tm_hour) + ":" + - String::FormatIntWidth2(time_struct->tm_min) + ":" + - String::FormatIntWidth2(time_struct->tm_sec); + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. @@ -3250,7 +3753,7 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, *stream << ""); - if (next_segment != NULL) { + if (next_segment != nullptr) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>& allowed_names = - GetReservedAttributesForElement(element_name); + GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) @@ -3280,30 +3783,47 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute( } // Prints an XML representation of a TestInfo object. -// TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, + const char* test_suite_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); - const std::string kTestcase = "testcase"; + const std::string kTestsuite = "testcase"; + + if (test_info.is_in_another_shard()) { + return; + } *stream << " \n"; + return; } - OutputXmlAttribute(stream, kTestcase, "status", + OutputXmlAttribute(stream, kTestsuite, "status", test_info.should_run() ? "run" : "notrun"); - OutputXmlAttribute(stream, kTestcase, "time", + OutputXmlAttribute(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "skipped" : "completed") + : "suppressed"); + OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(result.elapsed_time())); - OutputXmlAttribute(stream, kTestcase, "classname", test_case_name); - *stream << TestPropertiesAsXmlAttributes(result); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); + OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { @@ -3312,46 +3832,56 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, if (++failures == 1) { *stream << ">\n"; } - const string location = internal::FormatCompilerIndependentFileLocation( - part.file_name(), part.line_number()); - const string summary = location + "\n" + part.summary(); + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string summary = location + "\n" + part.summary(); *stream << " "; - const string detail = location + "\n" + part.message(); + const std::string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } - if (failures == 0) + if (failures == 0 && result.test_property_count() == 0) { *stream << " />\n"; - else + } else { + if (failures == 0) { + *stream << ">\n"; + } + OutputXmlTestProperties(stream, result); *stream << " \n"; + } } -// Prints an XML representation of a TestCase object -void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, - const TestCase& test_case) { +// Prints an XML representation of a TestSuite object +void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream, + const TestSuite& test_suite) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; - OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); + OutputXmlAttribute(stream, kTestsuite, "name", test_suite.name()); OutputXmlAttribute(stream, kTestsuite, "tests", - StreamableToString(test_case.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuite, "errors", "0"); - OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) - << ">\n"; - - for (int i = 0; i < test_case.total_test_count(); ++i) { - if (test_case.GetTestInfo(i)->is_reportable()) - OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + StreamableToString(test_suite.reportable_test_count())); + if (!GTEST_FLAG(list_tests)) { + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_suite.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_suite.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_suite.elapsed_time())); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp())); + *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result()); + } + *stream << ">\n"; + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) + OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } *stream << " \n"; } @@ -3372,25 +3902,46 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); + OutputXmlAttribute(stream, kTestsuites, "time", + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); - OutputXmlAttribute(stream, kTestsuites, "time", - FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } - *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - if (unit_test.GetTestCase(i)->reportable_test_count() > 0) - PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) + PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i)); + } + *stream << "\n"; +} + +void XmlUnitTestResultPrinter::PrintXmlTestsList( + std::ostream* stream, const std::vector& test_suites) { + const std::string kTestsuites = "testsuites"; + + *stream << "\n"; + *stream << "<" << kTestsuites; + + int total_tests = 0; + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); + } + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(total_tests)); + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + for (auto test_suite : test_suites) { + PrintXmlTestSuite(stream, *test_suite); } *stream << "\n"; } @@ -3408,8 +3959,403 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( return attributes.GetString(); } +void XmlUnitTestResultPrinter::OutputXmlTestProperties( + std::ostream* stream, const TestResult& result) { + const std::string kProperties = "properties"; + const std::string kProperty = "property"; + + if (result.test_property_count() <= 0) { + return; + } + + *stream << "<" << kProperties << ">\n"; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + *stream << "<" << kProperty; + *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; + *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; + *stream << "/>\n"; + } + *stream << "\n"; +} + // End XmlUnitTestResultPrinter +// This class generates an JSON output file. +class JsonUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit JsonUnitTestResultPrinter(const char* output_file); + + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + + // Prints an JSON summary of all unit tests. + static void PrintJsonTestList(::std::ostream* stream, + const std::vector& test_suites); + + private: + // Returns an JSON-escaped copy of the input string str. + static std::string EscapeJson(const std::string& str); + + //// Verifies that the given attribute belongs to the given element and + //// streams the attribute as JSON. + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma = true); + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma = true); + + // Streams a JSON representation of a TestInfo object. + static void OutputJsonTestInfo(::std::ostream* stream, + const char* test_suite_name, + const TestInfo& test_info); + + // Prints a JSON representation of a TestSuite object + static void PrintJsonTestSuite(::std::ostream* stream, + const TestSuite& test_suite); + + // Prints a JSON summary of unit_test to output stream out. + static void PrintJsonUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as + // a JSON dictionary. + static std::string TestPropertiesAsJson(const TestResult& result, + const std::string& indent); + + // The output file. + const std::string output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(JsonUnitTestResultPrinter); +}; + +// Creates a new JsonUnitTestResultPrinter. +JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "JSON output file may not be null"; + } +} + +void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* jsonout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintJsonUnitTest(&stream, unit_test); + fprintf(jsonout, "%s", StringStreamToString(&stream).c_str()); + fclose(jsonout); +} + +// Returns an JSON-escaped copy of the input string str. +std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) { + Message m; + + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '\\': + case '"': + case '/': + m << '\\' << ch; + break; + case '\b': + m << "\\b"; + break; + case '\t': + m << "\\t"; + break; + case '\n': + m << "\\n"; + break; + case '\f': + m << "\\f"; + break; + case '\r': + m << "\\r"; + break; + default: + if (ch < ' ') { + m << "\\u00" << String::FormatByte(static_cast(ch)); + } else { + m << ch; + } + break; + } + } + + return m.GetString(); +} + +// The following routines generate an JSON representation of a UnitTest +// object. + +// Formats the given time in milliseconds as seconds. +static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) { + ::std::stringstream ss; + ss << (static_cast(ms) * 1e-3) << "s"; + return ss.str(); +} + +// Converts the given epoch time in milliseconds to a date string in the +// RFC3339 format, without the timezone information. +static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) { + struct tm time_struct; + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec) + "Z"; +} + +static inline std::string Indent(size_t width) { + return std::string(width, ' '); +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedOutputAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\""; + if (comma) + *stream << ",\n"; +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedOutputAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": " << StreamableToString(value); + if (comma) + *stream << ",\n"; +} + +// Prints a JSON representation of a TestInfo object. +void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, + const char* test_suite_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const std::string kTestsuite = "testcase"; + const std::string kIndent = Indent(10); + + *stream << Indent(8) << "{\n"; + OutputJsonKey(stream, kTestsuite, "name", test_info.name(), kIndent); + + if (test_info.value_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "value_param", test_info.value_param(), + kIndent); + } + if (test_info.type_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "type_param", test_info.type_param(), + kIndent); + } + if (GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "file", test_info.file(), kIndent); + OutputJsonKey(stream, kTestsuite, "line", test_info.line(), kIndent, false); + *stream << "\n" << Indent(8) << "}"; + return; + } + + OutputJsonKey(stream, kTestsuite, "status", + test_info.should_run() ? "RUN" : "NOTRUN", kIndent); + OutputJsonKey(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "SKIPPED" : "COMPLETED") + : "SUPPRESSED", + kIndent); + OutputJsonKey(stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent); + OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent, + false); + *stream << TestPropertiesAsJson(result, kIndent); + + int failures = 0; + for (int i = 0; i < result.total_part_count(); ++i) { + const TestPartResult& part = result.GetTestPartResult(i); + if (part.failed()) { + *stream << ",\n"; + if (++failures == 1) { + *stream << kIndent << "\"" << "failures" << "\": [\n"; + } + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string message = EscapeJson(location + "\n" + part.message()); + *stream << kIndent << " {\n" + << kIndent << " \"failure\": \"" << message << "\",\n" + << kIndent << " \"type\": \"\"\n" + << kIndent << " }"; + } + } + + if (failures > 0) + *stream << "\n" << kIndent << "]"; + *stream << "\n" << Indent(8) << "}"; +} + +// Prints an JSON representation of a TestSuite object +void JsonUnitTestResultPrinter::PrintJsonTestSuite( + std::ostream* stream, const TestSuite& test_suite) { + const std::string kTestsuite = "testsuite"; + const std::string kIndent = Indent(6); + + *stream << Indent(4) << "{\n"; + OutputJsonKey(stream, kTestsuite, "name", test_suite.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "tests", test_suite.reportable_test_count(), + kIndent); + if (!GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "failures", + test_suite.failed_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "disabled", + test_suite.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); + OutputJsonKey( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(test_suite.elapsed_time()), + kIndent, false); + *stream << TestPropertiesAsJson(test_suite.ad_hoc_test_result(), kIndent) + << ",\n"; + } + + *stream << kIndent << "\"" << kTestsuite << "\": [\n"; + + bool comma = false; + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); + } + } + *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; +} + +// Prints a JSON summary of unit_test to output stream out. +void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + + OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "disabled", + unit_test.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent); + if (GTEST_FLAG(shuffle)) { + OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(), + kIndent); + } + OutputJsonKey(stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuites, "time", + FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent, + false); + + *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent) + << ",\n"; + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + bool comma = false; + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + PrintJsonTestSuite(stream, *unit_test.GetTestSuite(i)); + } + } + + *stream << "\n" << kIndent << "]\n" << "}\n"; +} + +void JsonUnitTestResultPrinter::PrintJsonTestList( + std::ostream* stream, const std::vector& test_suites) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + int total_tests = 0; + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); + } + OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent); + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + for (size_t i = 0; i < test_suites.size(); ++i) { + if (i != 0) { + *stream << ",\n"; + } + PrintJsonTestSuite(stream, *test_suites[i]); + } + + *stream << "\n" + << kIndent << "]\n" + << "}\n"; +} +// Produces a string representing the test properties in a result as +// a JSON dictionary. +std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( + const TestResult& result, const std::string& indent) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << ",\n" << indent << "\"" << property.key() << "\": " + << "\"" << EscapeJson(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End JsonUnitTestResultPrinter + #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, @@ -3417,8 +4363,8 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. -string StreamingListener::UrlEncode(const char* str) { - string result; +std::string StreamingListener::UrlEncode(const char* str) { + std::string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { @@ -3444,7 +4390,7 @@ void StreamingListener::SocketWriter::MakeConnection() { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; - addrinfo* servinfo = NULL; + addrinfo* servinfo = nullptr; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. @@ -3456,7 +4402,7 @@ void StreamingListener::SocketWriter::MakeConnection() { } // Loop through all the results and connect to the first we can. - for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr; cur_addr = cur_addr->ai_next) { sockfd_ = socket( cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); @@ -3480,58 +4426,82 @@ void StreamingListener::SocketWriter::MakeConnection() { // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ -// Class ScopedTrace +// class OsStackTraceGetter -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message = message.GetString(); +const char* const OsStackTraceGetterInterface::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; - UnitTest::GetInstance()->PushGTestTrace(trace); -} +std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) + GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + std::string result; -// Pops the info pushed by the c'tor. -ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - UnitTest::GetInstance()->PopGTestTrace(); -} + if (max_depth <= 0) { + return result; + } + max_depth = std::min(max_depth, kMaxStackTraceDepth); -// class OsStackTraceGetter + std::vector raw_stack(max_depth); + // Skips the frames requested by the caller, plus this function. + const int raw_stack_size = + absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1); -// Returns the current OS stack trace as an std::string. Parameters: -// -// max_depth - the maximum number of stack frames to be included -// in the trace. -// skip_count - the number of top frames to be skipped; doesn't count -// against max_depth. -// -string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, - int /* skip_count */) - GTEST_LOCK_EXCLUDED_(mutex_) { + void* caller_frame = nullptr; + { + MutexLock lock(&mutex_); + caller_frame = caller_frame_; + } + + for (int i = 0; i < raw_stack_size; ++i) { + if (raw_stack[i] == caller_frame && + !GTEST_FLAG(show_internal_stack_frames)) { + // Add a marker to the trace and stop adding frames. + absl::StrAppend(&result, kElidedFramesMarker, "\n"); + break; + } + + char tmp[1024]; + const char* symbol = "(unknown)"; + if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) { + symbol = tmp; + } + + char line[1024]; + snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol); + result += line; + } + + return result; + +#else // !GTEST_HAS_ABSL + static_cast(max_depth); + static_cast(skip_count); return ""; +#endif // GTEST_HAS_ABSL } -void OsStackTraceGetter::UponLeavingGTest() - GTEST_LOCK_EXCLUDED_(mutex_) { -} +void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + void* caller_frame = nullptr; + if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) { + caller_frame = nullptr; + } -const char* const -OsStackTraceGetter::kElidedFramesMarker = - "... " GTEST_NAME_ " internal frames ..."; + MutexLock lock(&mutex_); + caller_frame_ = caller_frame; +#endif // GTEST_HAS_ABSL +} // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) - : premature_exit_filepath_(premature_exit_filepath) { + : premature_exit_filepath_(premature_exit_filepath ? + premature_exit_filepath : "") { // If a path to the premature-exit file is specified... - if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { + if (!premature_exit_filepath_.empty()) { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. @@ -3542,13 +4512,18 @@ class ScopedPrematureExitFile { } ~ScopedPrematureExitFile() { - if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { - remove(premature_exit_filepath_); + if (!premature_exit_filepath_.empty()) { + int retval = remove(premature_exit_filepath_.c_str()); + if (retval) { + GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \"" + << premature_exit_filepath_ << "\" with error " + << retval; + } } } private: - const char* const premature_exit_filepath_; + const std::string premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; @@ -3559,9 +4534,8 @@ class ScopedPrematureExitFile { TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), - default_result_printer_(NULL), - default_xml_generator_(NULL) { -} + default_result_printer_(nullptr), + default_xml_generator_(nullptr) {} TestEventListeners::~TestEventListeners() { delete repeater_; } @@ -3578,9 +4552,9 @@ void TestEventListeners::Append(TestEventListener* listener) { // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) - default_result_printer_ = NULL; + default_result_printer_ = nullptr; else if (listener == default_xml_generator_) - default_xml_generator_ = NULL; + default_xml_generator_ = nullptr; return repeater_->Release(listener); } @@ -3599,8 +4573,7 @@ void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { // list. delete Release(default_result_printer_); default_result_printer_ = listener; - if (listener != NULL) - Append(listener); + if (listener != nullptr) Append(listener); } } @@ -3615,8 +4588,7 @@ void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; - if (listener != NULL) - Append(listener); + if (listener != nullptr) Append(listener); } } @@ -3640,52 +4612,66 @@ void TestEventListeners::SuppressEventForwarding() { // call this before main() starts, from which point on the return // value will never change. UnitTest* UnitTest::GetInstance() { - // When compiled with MSVC 7.1 in optimized mode, destroying the - // UnitTest object upon exiting the program messes up the exit code, - // causing successful tests to appear failed. We have to use a - // different implementation in this case to bypass the compiler bug. - // This implementation makes the compiler happy, at the cost of - // leaking the UnitTest object. - // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. -#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +#if defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; -#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +#endif // defined(__BORLANDC__) } -// Gets the number of successful test cases. -int UnitTest::successful_test_case_count() const { - return impl()->successful_test_case_count(); +// Gets the number of successful test suites. +int UnitTest::successful_test_suite_count() const { + return impl()->successful_test_suite_count(); } -// Gets the number of failed test cases. -int UnitTest::failed_test_case_count() const { - return impl()->failed_test_case_count(); +// Gets the number of failed test suites. +int UnitTest::failed_test_suite_count() const { + return impl()->failed_test_suite_count(); } -// Gets the number of all test cases. -int UnitTest::total_test_case_count() const { - return impl()->total_test_case_count(); +// Gets the number of all test suites. +int UnitTest::total_test_suite_count() const { + return impl()->total_test_suite_count(); } -// Gets the number of all test cases that contain at least one test +// Gets the number of all test suites that contain at least one test // that should run. +int UnitTest::test_suite_to_run_count() const { + return impl()->test_suite_to_run_count(); +} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_suite_count(); +} +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_suite_count(); +} +int UnitTest::total_test_case_count() const { + return impl()->total_test_suite_count(); +} int UnitTest::test_case_to_run_count() const { - return impl()->test_case_to_run_count(); + return impl()->test_suite_to_run_count(); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } +// Gets the number of skipped tests. +int UnitTest::skipped_test_count() const { + return impl()->skipped_test_count(); +} + // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } @@ -3721,29 +4707,37 @@ internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } -// Returns true iff the unit test passed (i.e. all test cases passed). +// Returns true if and only if the unit test passed (i.e. all test suites +// passed). bool UnitTest::Passed() const { return impl()->Passed(); } -// Returns true iff the unit test failed (i.e. some test case failed -// or something outside of all tests failed). +// Returns true if and only if the unit test failed (i.e. some test suite +// failed or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +const TestSuite* UnitTest::GetTestSuite(int i) const { + return impl()->GetTestSuite(i); +} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the TestResult containing information on test failures and -// properties logged outside of individual test cases. +// properties logged outside of individual test suites. const TestResult& UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -TestCase* UnitTest::GetMutableTestCase(int i) { - return impl()->GetMutableTestCase(i); +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +TestSuite* UnitTest::GetMutableTestSuite(int i) { + return impl()->GetMutableSuiteCase(i); } // Returns the list of event listeners that can be used to track events @@ -3763,8 +4757,8 @@ TestEventListeners& UnitTest::listeners() { // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { - if (env == NULL) { - return NULL; + if (env == nullptr) { + return nullptr; } impl_->environments().push_back(env); @@ -3788,42 +4782,45 @@ void UnitTest::AddTestPartResult( if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; - for (int i = static_cast(impl_->gtest_trace_stack().size()); - i > 0; --i) { + for (size_t i = impl_->gtest_trace_stack().size(); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } - if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + if (os_stack_trace.c_str() != nullptr && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } - const TestPartResult result = - TestPartResult(result_type, file_name, line_number, - msg.GetString().c_str()); + const TestPartResult result = TestPartResult( + result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); - if (result_type != TestPartResult::kSuccess) { + if (result_type != TestPartResult::kSuccess && + result_type != TestPartResult::kSkip) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); +#elif (!defined(__native_client__)) && \ + ((defined(__clang__) || defined(__GNUC__)) && \ + (defined(__x86_64__) || defined(__i386__))) + // with clang/gcc we can achieve the same effect on x86 by invoking int3 + asm("int3"); #else - // Dereference NULL through a volatile pointer to prevent the compiler + // Dereference nullptr through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for - // portability: Symbian doesn't implement abort() well, and some debuggers - // don't correctly trap abort(). - *static_cast(NULL) = 1; + // portability: some debuggers don't correctly trap abort(). + *static_cast(nullptr) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS @@ -3838,8 +4835,8 @@ void UnitTest::AddTestPartResult( } // Adds a TestProperty to the current TestResult object when invoked from -// inside a test, to current TestCase's ad_hoc_test_result_ when invoked -// from SetUpTestCase or TearDownTestCase, or to the global property set +// inside a test, to current TestSuite's ad_hoc_test_result_ when invoked +// from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void UnitTest::RecordProperty(const std::string& key, @@ -3878,20 +4875,21 @@ int UnitTest::Run() { // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( - in_death_test_child_process ? - NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); + in_death_test_child_process + ? nullptr + : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); -#if GTEST_HAS_SEH +#if GTEST_OS_WINDOWS // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { -# if !GTEST_OS_WINDOWS_MOBILE +# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -3904,25 +4902,29 @@ int UnitTest::Run() { _set_error_mode(_OUT_TO_STDERR); # endif -# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +# if defined(_MSC_VER) && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. - // - // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. - // Users of prior VC versions shall suffer the agony and pain of - // clicking through the countless debug dialogs. - // TODO(vladl@google.com): find a way to suppress the abort dialog() in the - // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif + + // In debug mode, the Windows CRT can crash with an assertion over invalid + // input (e.g. passing an invalid file descriptor). The default handling + // for these assertions is to pop up a dialog and wait for user input. + // Instead ask the CRT to dump such assertions to stderr non-interactively. + if (!IsDebuggerPresent()) { + (void)_CrtSetReportMode(_CRT_ASSERT, + _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + } } -#endif // GTEST_HAS_SEH +#endif // GTEST_OS_WINDOWS return internal::HandleExceptionsInMethodIfSupported( impl(), @@ -3936,13 +4938,22 @@ const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } -// Returns the TestCase object for the test that's currently running, +// Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. +const TestSuite* UnitTest::current_test_suite() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_suite(); +} + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* UnitTest::current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); - return impl_->current_test_case(); + return impl_->current_test_suite(); } +#endif // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. @@ -3955,15 +4966,12 @@ const TestInfo* UnitTest::current_test_info() const // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } -#if GTEST_HAS_PARAM_TEST -// Returns ParameterizedTestCaseRegistry object used to keep track of +// Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. -internal::ParameterizedTestCaseRegistry& - UnitTest::parameterized_test_registry() - GTEST_LOCK_EXCLUDED_(mutex_) { +internal::ParameterizedTestSuiteRegistry& +UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } -#endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { @@ -3994,33 +5002,23 @@ namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4355) // Temporarily disables warning 4355 - // (using this in initializer). - default_global_test_part_result_reporter_(this), + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) + default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), -# pragma warning(pop) // Restores the warning state again. -#else - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -#endif // _MSC_VER - global_test_part_result_repoter_( + GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), -#if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), -#endif // GTEST_HAS_PARAM_TEST - last_death_test_case_(-1), - current_test_case_(NULL), - current_test_info_(NULL), + last_death_test_suite_(-1), + current_test_suite_(nullptr), + current_test_info_(nullptr), ad_hoc_test_result_(), - os_stack_trace_getter_(NULL), + os_stack_trace_getter_(nullptr), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. - random_(0), // Will be reseeded before first use. + random_(0), // Will be reseeded before first use. start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST @@ -4032,8 +5030,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) } UnitTestImpl::~UnitTestImpl() { - // Deletes every TestCase. - ForEach(test_cases_, internal::Delete); + // Deletes every TestSuite. + ForEach(test_suites_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); @@ -4042,20 +5040,20 @@ UnitTestImpl::~UnitTestImpl() { } // Adds a TestProperty to the current TestResult object when invoked in a -// context of a test, to current test case's ad_hoc_test_result when invoke -// from SetUpTestCase/TearDownTestCase, or to the global property set +// context of a test, to current test suite's ad_hoc_test_result when invoke +// from SetUpTestSuite/TearDownTestSuite, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. void UnitTestImpl::RecordProperty(const TestProperty& test_property) { std::string xml_element; TestResult* test_result; // TestResult appropriate for property recording. - if (current_test_info_ != NULL) { + if (current_test_info_ != nullptr) { xml_element = "testcase"; test_result = &(current_test_info_->result_); - } else if (current_test_case_ != NULL) { + } else if (current_test_suite_ != nullptr) { xml_element = "testsuite"; - test_result = &(current_test_case_->ad_hoc_test_result_); + test_result = &(current_test_suite_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; @@ -4067,7 +5065,7 @@ void UnitTestImpl::RecordProperty(const TestProperty& test_property) { // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { - if (internal_run_death_test_flag_.get() != NULL) + if (internal_run_death_test_flag_.get() != nullptr) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST @@ -4079,10 +5077,12 @@ void UnitTestImpl::ConfigureXmlOutput() { if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format == "json") { + listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \"" + << output_format << "\" ignored."; } } @@ -4097,9 +5097,8 @@ void UnitTestImpl::ConfigureStreamingOutput() { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { - printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", - target.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target + << "\" ignored."; } } } @@ -4115,6 +5114,11 @@ void UnitTestImpl::PostFlagParsingInit() { if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; +#if defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + // Register to send notifications about key process state changes. + listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_()); +#endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); @@ -4133,77 +5137,83 @@ void UnitTestImpl::PostFlagParsingInit() { // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ + +#if GTEST_HAS_ABSL + if (GTEST_FLAG(install_failure_signal_handler)) { + absl::FailureSignalHandlerOptions options; + absl::InstallFailureSignalHandler(options); + } +#endif // GTEST_HAS_ABSL } } -// A predicate that checks the name of a TestCase against a known +// A predicate that checks the name of a TestSuite against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // -// TestCaseNameIs is copyable. -class TestCaseNameIs { +// TestSuiteNameIs is copyable. +class TestSuiteNameIs { public: // Constructor. - explicit TestCaseNameIs(const std::string& name) - : name_(name) {} + explicit TestSuiteNameIs(const std::string& name) : name_(name) {} - // Returns true iff the name of test_case matches name_. - bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + // Returns true if and only if the name of test_suite matches name_. + bool operator()(const TestSuite* test_suite) const { + return test_suite != nullptr && + strcmp(test_suite->name(), name_.c_str()) == 0; } private: std::string name_; }; -// Finds and returns a TestCase with the given name. If one doesn't +// Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // -// test_case_name: name of the test case -// type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) { - // Can we find a TestCase with the given name? - const std::vector::const_iterator test_case = - std::find_if(test_cases_.begin(), test_cases_.end(), - TestCaseNameIs(test_case_name)); - - if (test_case != test_cases_.end()) - return *test_case; +// test_suite_name: name of the test suite +// type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite* UnitTestImpl::GetTestSuite( + const char* test_suite_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + // Can we find a TestSuite with the given name? + const auto test_suite = + std::find_if(test_suites_.rbegin(), test_suites_.rend(), + TestSuiteNameIs(test_suite_name)); + + if (test_suite != test_suites_.rend()) return *test_suite; // No. Let's create one. - TestCase* const new_test_case = - new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); - - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(test_case_name, - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. This only works when the test cases haven't + auto* const new_test_suite = + new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test suite? + if (internal::UnitTestOptions::MatchesFilter(test_suite_name, + kDeathTestSuiteFilter)) { + // Yes. Inserts the test suite after the last death test suite + // defined so far. This only works when the test suites haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. - ++last_death_test_case_; - test_cases_.insert(test_cases_.begin() + last_death_test_case_, - new_test_case); + ++last_death_test_suite_; + test_suites_.insert(test_suites_.begin() + last_death_test_suite_, + new_test_suite); } else { // No. Appends to the end of the list. - test_cases_.push_back(new_test_case); + test_suites_.push_back(new_test_suite); } - test_case_indices_.push_back(static_cast(test_case_indices_.size())); - return new_test_case; + test_suite_indices_.push_back(static_cast(test_suite_indices_.size())); + return new_test_suite; } // Helpers for setting up / tearing down the given environment. They @@ -4221,13 +5231,9 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); } // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { - // Makes sure InitGoogleTest() was called. - if (!GTestIsInitialized()) { - printf("%s", - "\nThis test program did NOT call ::testing::InitGoogleTest " - "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return false; - } + // True if and only if Google Test is initialized before RUN_ALL_TESTS() is + // called. + const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized(); // Do not run any test if the --help flag was specified. if (g_help_flag) @@ -4242,12 +5248,18 @@ bool UnitTestImpl::RunAllTests() { // protocol. internal::WriteToShardStatusFileIfNeeded(); - // True iff we are in a subprocess for running a thread-safe-style + // True if and only if we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST - in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); + in_subprocess_for_death_test = + (internal_run_death_test_flag_.get() != nullptr); +# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) + if (in_subprocess_for_death_test) { + GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_(); + } +# endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, @@ -4269,7 +5281,7 @@ bool UnitTestImpl::RunAllTests() { random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; - // True iff at least one test has failed. + // True if and only if at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); @@ -4281,17 +5293,17 @@ bool UnitTestImpl::RunAllTests() { // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. - const bool forever = repeat < 0; - for (int i = 0; forever || i != repeat; i++) { + const bool gtest_repeat_forever = repeat < 0; + for (int i = 0; gtest_repeat_forever || i != repeat; i++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); - // Shuffles test cases and tests if requested. + // Shuffles test suites and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { - random()->Reseed(random_seed_); + random()->Reseed(static_cast(random_seed_)); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. @@ -4301,19 +5313,33 @@ bool UnitTestImpl::RunAllTests() { // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); - // Runs each test case if there is at least one test to run. + // Runs each test suite if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); - // Runs the tests only if there was no fatal failure during global - // set-up. - if (!Test::HasFatalFailure()) { - for (int test_index = 0; test_index < total_test_case_count(); + // Runs the tests only if there was no fatal failure or skip triggered + // during global set-up. + if (Test::IsSkipped()) { + // Emit diagnostics when global set-up calls skip, as it will not be + // emitted by default. + TestResult& test_result = + *internal::GetUnitTestImpl()->current_test_result(); + for (int j = 0; j < test_result.total_part_count(); ++j) { + const TestPartResult& test_part_result = + test_result.GetTestPartResult(j); + if (test_part_result.type() == TestPartResult::kSkip) { + const std::string& result = test_part_result.message(); + printf("%s\n", result.c_str()); + } + } + fflush(stdout); + } else if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_suite_count(); test_index++) { - GetMutableTestCase(test_index)->Run(); + GetMutableSuiteCase(test_index)->Run(); } } @@ -4350,6 +5376,20 @@ bool UnitTestImpl::RunAllTests() { repeater->OnTestProgramEnd(*parent_); + if (!gtest_is_initialized_before_run_all_tests) { + ColoredPrintf( + COLOR_RED, + "\nIMPORTANT NOTICE - DO NOT IGNORE:\n" + "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_ + "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_ + " will start to enforce the valid usage. " + "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT +#if GTEST_FOR_GOOGLE_ + ColoredPrintf(COLOR_RED, + "For more details, see http://wiki/Main/ValidGUnitMain.\n"); +#endif // GTEST_FOR_GOOGLE_ + } + return !failed; } @@ -4359,9 +5399,9 @@ bool UnitTestImpl::RunAllTests() { // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); - if (test_shard_file != NULL) { + if (test_shard_file != nullptr) { FILE* const file = posix::FOpen(test_shard_file, "w"); - if (file == NULL) { + if (file == nullptr) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", @@ -4396,7 +5436,7 @@ bool ShouldShard(const char* total_shards_env, << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { @@ -4404,7 +5444,7 @@ bool ShouldShard(const char* total_shards_env, << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { @@ -4413,7 +5453,7 @@ bool ShouldShard(const char* total_shards_env, << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } @@ -4426,7 +5466,7 @@ bool ShouldShard(const char* total_shards_env, // and aborts. Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { const char* str_val = posix::GetEnv(var); - if (str_val == NULL) { + if (str_val == nullptr) { return default_val; } @@ -4439,8 +5479,8 @@ Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { } // Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; @@ -4448,11 +5488,11 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in -// each TestCase and TestInfo object. +// each TestSuite and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see -// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. -// Returns the number of tests that should run. +// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md +// . Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; @@ -4465,42 +5505,40 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; - for (size_t i = 0; i < test_cases_.size(); i++) { - TestCase* const test_case = test_cases_[i]; - const std::string &test_case_name = test_case->name(); - test_case->set_should_run(false); + for (auto* test_suite : test_suites_) { + const std::string& test_suite_name = test_suite->name(); + test_suite->set_should_run(false); - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - TestInfo* const test_info = test_case->test_info_list()[j]; + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + TestInfo* const test_info = test_suite->test_info_list()[j]; const std::string test_name(test_info->name()); - // A test is disabled if test case name or test name matches + // A test is disabled if test suite name or test name matches // kDisableTestFilter. - const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); + const bool is_disabled = internal::UnitTestOptions::MatchesFilter( + test_suite_name, kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter( + test_name, kDisableTestFilter); test_info->is_disabled_ = is_disabled; - const bool matches_filter = - internal::UnitTestOptions::FilterMatchesTest(test_case_name, - test_name); + const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest( + test_suite_name, test_name); test_info->matches_filter_ = matches_filter; const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; - const bool is_selected = is_runnable && - (shard_tests == IGNORE_SHARDING_PROTOCOL || - ShouldRunTestOnShard(total_shards, shard_index, - num_runnable_tests)); + const bool is_in_another_shard = + shard_tests != IGNORE_SHARDING_PROTOCOL && + !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests); + test_info->is_in_another_shard_ = is_in_another_shard; + const bool is_selected = is_runnable && !is_in_another_shard; num_runnable_tests += is_runnable; num_selected_tests += is_selected; test_info->should_run_ = is_selected; - test_case->set_should_run(test_case->should_run() || is_selected); + test_suite->set_should_run(test_suite->should_run() || is_selected); } } return num_selected_tests; @@ -4511,7 +5549,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // max_length characters, only prints the first max_length characters // and "...". static void PrintOnOneLine(const char* str, int max_length) { - if (str != NULL) { + if (str != nullptr) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); @@ -4533,27 +5571,25 @@ void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; - for (size_t i = 0; i < test_cases_.size(); i++) { - const TestCase* const test_case = test_cases_[i]; - bool printed_test_case_name = false; + for (auto* test_suite : test_suites_) { + bool printed_test_suite_name = false; - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - const TestInfo* const test_info = - test_case->test_info_list()[j]; + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + const TestInfo* const test_info = test_suite->test_info_list()[j]; if (test_info->matches_filter_) { - if (!printed_test_case_name) { - printed_test_case_name = true; - printf("%s.", test_case->name()); - if (test_case->type_param() != NULL) { + if (!printed_test_suite_name) { + printed_test_suite_name = true; + printf("%s.", test_suite->name()); + if (test_suite->type_param() != nullptr) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. - PrintOnOneLine(test_case->type_param(), kMaxParamLength); + PrintOnOneLine(test_suite->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); - if (test_info->value_param() != NULL) { + if (test_info->value_param() != nullptr) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. @@ -4564,6 +5600,23 @@ void UnitTestImpl::ListTestsMatchingFilter() { } } fflush(stdout); + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml" || output_format == "json") { + FILE* fileout = OpenFileForWriting( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); + std::stringstream stream; + if (output_format == "xml") { + XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintXmlTestsList(&stream, test_suites_); + } else if (output_format == "json") { + JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintJsonTestList(&stream, test_suites_); + } + fprintf(fileout, "%s", StringStreamToString(&stream).c_str()); + fclose(fileout); + } } // Sets the OS stack trace getter. @@ -4583,43 +5636,51 @@ void UnitTestImpl::set_os_stack_trace_getter( // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { - if (os_stack_trace_getter_ == NULL) { + if (os_stack_trace_getter_ == nullptr) { +#ifdef GTEST_OS_STACK_TRACE_GETTER_ + os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_; +#else os_stack_trace_getter_ = new OsStackTraceGetter; +#endif // GTEST_OS_STACK_TRACE_GETTER_ } return os_stack_trace_getter_; } -// Returns the TestResult for the test that's currently running, or -// the TestResult for the ad hoc test if no test is running. +// Returns the most specific TestResult currently running. TestResult* UnitTestImpl::current_test_result() { - return current_test_info_ ? - &(current_test_info_->result_) : &ad_hoc_test_result_; + if (current_test_info_ != nullptr) { + return ¤t_test_info_->result_; + } + if (current_test_suite_ != nullptr) { + return ¤t_test_suite_->ad_hoc_test_result_; + } + return &ad_hoc_test_result_; } -// Shuffles all test cases, and the tests within each test case, +// Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { - // Shuffles the death test cases. - ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + // Shuffles the death test suites. + ShuffleRange(random(), 0, last_death_test_suite_ + 1, &test_suite_indices_); - // Shuffles the non-death test cases. - ShuffleRange(random(), last_death_test_case_ + 1, - static_cast(test_cases_.size()), &test_case_indices_); + // Shuffles the non-death test suites. + ShuffleRange(random(), last_death_test_suite_ + 1, + static_cast(test_suites_.size()), &test_suite_indices_); - // Shuffles the tests inside each test case. - for (size_t i = 0; i < test_cases_.size(); i++) { - test_cases_[i]->ShuffleTests(random()); + // Shuffles the tests inside each test suite. + for (auto& test_suite : test_suites_) { + test_suite->ShuffleTests(random()); } } -// Restores the test cases and tests to their order before the first shuffle. +// Restores the test suites and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { - for (size_t i = 0; i < test_cases_.size(); i++) { - // Unshuffles the tests in each test case. - test_cases_[i]->UnshuffleTests(); - // Resets the index of each test case. - test_case_indices_[i] = static_cast(i); + for (size_t i = 0; i < test_suites_.size(); i++) { + // Unshuffles the tests in each test suite. + test_suites_[i]->UnshuffleTests(); + // Resets the index of each test suite. + test_suite_indices_[i] = static_cast(i); } } @@ -4675,16 +5736,15 @@ bool SkipPrefix(const char* prefix, const char** pstr) { // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. -const char* ParseFlagValue(const char* str, - const char* flag, - bool def_optional) { +static const char* ParseFlagValue(const char* str, const char* flag, + bool def_optional) { // str and flag must not be NULL. - if (str == NULL || flag == NULL) return NULL; + if (str == nullptr || flag == nullptr) return nullptr; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); - if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; // Skips the flag name. const char* flag_end = str + flag_len; @@ -4697,7 +5757,7 @@ const char* ParseFlagValue(const char* str, // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. - if (flag_end[0] != '=') return NULL; + if (flag_end[0] != '=') return nullptr; // Returns the string after "=". return flag_end + 1; @@ -4713,12 +5773,12 @@ const char* ParseFlagValue(const char* str, // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseBoolFlag(const char* str, const char* flag, bool* value) { +static bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); @@ -4735,7 +5795,7 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, @@ -4747,12 +5807,13 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseStringFlag(const char* str, const char* flag, std::string* value) { +template +static bool ParseStringFlag(const char* str, const char* flag, String* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Sets *value to the value of the flag. *value = value_str; @@ -4783,8 +5844,6 @@ static bool HasGoogleTestFlagPrefix(const char* str) { // @Y changes the color to yellow. // @D changes to the default terminal text color. // -// TODO(wan@google.com): Write tests for this once we add stdout -// capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. @@ -4794,7 +5853,7 @@ static void PrintColorEncoded(const char* str) { // next segment. for (;;) { const char* p = strchr(str, '@'); - if (p == NULL) { + if (p == nullptr) { ColoredPrintf(color, "%s", str); return; } @@ -4849,24 +5908,25 @@ static const char kColorEncodedHelpMessage[] = " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" +" @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate an XML report in the given directory or with the given file\n" -" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -#if GTEST_CAN_STREAM_RESULTS_ +" Generate a JSON or XML report in the given directory or with the given\n" +" file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n" +# if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" -#endif // GTEST_CAN_STREAM_RESULTS_ +# endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" -#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" -#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions.\n" +" Turn assertion failures into C++ exceptions for use by an external\n" +" test framework.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" @@ -4883,6 +5943,56 @@ static const char kColorEncodedHelpMessage[] = "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; +static bool ParseGoogleTestFlag(const char* const arg) { + return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)); +} + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +static void LoadFlagsFromFile(const std::string& path) { + FILE* flagfile = posix::FOpen(path.c_str(), "r"); + if (!flagfile) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile) + << "\""; + } + std::string contents(ReadEntireFile(flagfile)); + posix::FClose(flagfile); + std::vector lines; + SplitString(contents, '\n', &lines); + for (size_t i = 0; i < lines.size(); ++i) { + if (lines[i].empty()) + continue; + if (!ParseGoogleTestFlag(lines[i].c_str())) + g_help_flag = true; + } +} +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. @@ -4896,35 +6006,24 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { using internal::ParseInt32Flag; using internal::ParseStringFlag; - // Do we see a Google Test flag? - if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, - >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseStringFlag(arg, kStreamResultToFlag, - >EST_FLAG(stream_result_to)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, - >EST_FLAG(throw_on_failure)) - ) { - // Yes. Shift the remainder of the argv list left by one. Note + bool remove_flag = false; + if (ParseGoogleTestFlag(arg)) { + remove_flag = true; +#if GTEST_USE_OWN_FLAGFILE_FLAG_ + } else if (ParseStringFlag(arg, kFlagfileFlag, >EST_FLAG(flagfile))) { + LoadFlagsFromFile(GTEST_FLAG(flagfile)); + remove_flag = true; +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + + if (remove_flag) { + // Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. @@ -4938,12 +6037,6 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // We also need to decrement the iterator as we just removed // an element. i--; - } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?" || - HasGoogleTestFlagPrefix(arg)) { - // Both help flag and unrecognized Google Test flags (excluding - // internal ones) trigger help display. - g_help_flag = true; } } @@ -4959,6 +6052,17 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); + + // Fix the value of *_NSGetArgc() on macOS, but if and only if + // *_NSGetArgv() == argv + // Only applicable to char** version of argv +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS + if (*_NSGetArgv() == argv) { + *_NSGetArgc() = *argc; + } +#endif +#endif } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); @@ -4970,23 +6074,19 @@ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { - g_init_gtest_count++; - // We don't want to run the initialization code twice. - if (g_init_gtest_count != 1) return; + if (GTestIsInitialized()) return; if (*argc <= 0) return; - internal::g_executable_path = internal::StreamableToString(argv[0]); - -#if GTEST_HAS_DEATH_TEST - g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } -#endif // GTEST_HAS_DEATH_TEST +#if GTEST_HAS_ABSL + absl::InitializeSymbolizer(g_argvs[0].c_str()); +#endif // GTEST_HAS_ABSL ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); @@ -5004,13 +6104,78 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +void InitGoogleTest() { + // Since Arduino doesn't have a command line, fake out the argc/argv arguments + int argc = 1; + const auto arg0 = "dummy"; + char* argv0 = const_cast(arg0); + char** argv = &argv0; + +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(&argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + internal::InitGoogleTestImpl(&argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + +std::string TempDir() { +#if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) + return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + return "\\temp\\"; +#elif GTEST_OS_WINDOWS + const char* temp_dir = internal::posix::GetEnv("TEMP"); + if (temp_dir == nullptr || temp_dir[0] == '\0') + return "\\temp\\"; + else if (temp_dir[strlen(temp_dir) - 1] == '\\') + return temp_dir; + else + return std::string(temp_dir) + "\\"; +#elif GTEST_OS_LINUX_ANDROID + return "/sdcard/"; +#else + return "/tmp/"; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +void ScopedTrace::PushTrace(const char* file, int line, std::string message) { + internal::TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message.swap(message); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + UnitTest::GetInstance()->PopGTestTrace(); } } // namespace testing diff --git a/test/gtest/src/gtest_main.cc b/test/gtest/src/gtest_main.cc index 94540b128b..f6e1dd96fb 100644 --- a/test/gtest/src/gtest_main.cc +++ b/test/gtest/src/gtest_main.cc @@ -27,12 +27,21 @@ // (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 // NOLINT - +#include #include "gtest/gtest.h" -GTEST_API_ int main(int argc, char **argv) { // NOLINT - printf("Running main() from gtest_main.cc\n"); +#ifdef ARDUINO +void setup() { + testing::InitGoogleTest(); +} + +void loop() { RUN_ALL_TESTS(); } + +#else + +GTEST_API_ int main(int argc, char **argv) { + printf("Running main() from %s\n", __FILE__); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } +#endif diff --git a/test/integration/diff_drive_system.cc b/test/integration/diff_drive_system.cc index 1a1d2888ff..1d55d2b576 100644 --- a/test/integration/diff_drive_system.cc +++ b/test/integration/diff_drive_system.cc @@ -310,6 +310,113 @@ TEST_P(DiffDriveTest, SkidPublishCmd) EXPECT_LT(poses[0].Rot().Z(), poses[3999].Rot().Z()); } +///////////////////////////////////////////////// +TEST_P(DiffDriveTest, OdomFrameId) +{ + // Start server + ServerConfig serverConfig; + serverConfig.SetSdfFile(std::string(PROJECT_SOURCE_PATH) + + "/test/worlds/diff_drive.sdf"); + + Server server(serverConfig); + EXPECT_FALSE(server.Running()); + EXPECT_FALSE(*server.Running(0)); + + server.SetUpdatePeriod(0ns); + + unsigned int odomPosesCount = 0; + std::function odomCb = + [&odomPosesCount](const msgs::Odometry &_msg) + { + ASSERT_TRUE(_msg.has_header()); + ASSERT_TRUE(_msg.header().has_stamp()); + + ASSERT_GT(_msg.header().data_size(), 1); + + EXPECT_STREQ(_msg.header().data(0).key().c_str(), "frame_id"); + EXPECT_STREQ( + _msg.header().data(0).value().Get(0).c_str(), "vehicle/odom"); + + EXPECT_STREQ(_msg.header().data(1).key().c_str(), "child_frame_id"); + EXPECT_STREQ( + _msg.header().data(1).value().Get(0).c_str(), "vehicle/chassis"); + + odomPosesCount++; + }; + + transport::Node node; + auto pub = node.Advertise("/model/vehicle/cmd_vel"); + node.Subscribe("/model/vehicle/odometry", odomCb); + + msgs::Twist msg; + msgs::Set(msg.mutable_linear(), math::Vector3d(0.5, 0, 0)); + msgs::Set(msg.mutable_angular(), math::Vector3d(0.0, 0, 0.2)); + + pub.Publish(msg); + + server.Run(true, 100, false); + + int sleep = 0; + int maxSleep = 30; + for (; odomPosesCount < 5 && sleep < maxSleep; ++sleep) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + ASSERT_NE(maxSleep, sleep); + + EXPECT_EQ(5u, odomPosesCount); +} + +///////////////////////////////////////////////// +TEST_P(DiffDriveTest, OdomCustomFrameId) +{ + // Start server + ServerConfig serverConfig; + serverConfig.SetSdfFile(std::string(PROJECT_SOURCE_PATH) + + "/test/worlds/diff_drive_custom_frame_id.sdf"); + + Server server(serverConfig); + EXPECT_FALSE(server.Running()); + EXPECT_FALSE(*server.Running(0)); + + server.SetUpdatePeriod(0ns); + + unsigned int odomPosesCount = 0; + std::function odomCb = + [&odomPosesCount](const msgs::Odometry &_msg) + { + ASSERT_TRUE(_msg.has_header()); + ASSERT_TRUE(_msg.header().has_stamp()); + + ASSERT_GT(_msg.header().data_size(), 1); + + EXPECT_STREQ(_msg.header().data(0).key().c_str(), "frame_id"); + EXPECT_STREQ(_msg.header().data(0).value().Get(0).c_str(), "odom"); + + EXPECT_STREQ(_msg.header().data(1).key().c_str(), "child_frame_id"); + EXPECT_STREQ( + _msg.header().data(1).value().Get(0).c_str(), "base_footprint"); + + odomPosesCount++; + }; + + transport::Node node; + auto pub = node.Advertise("/model/vehicle/cmd_vel"); + node.Subscribe("/model/vehicle/odometry", odomCb); + + server.Run(true, 100, false); + + int sleep = 0; + int maxSleep = 30; + for (; odomPosesCount < 5 && sleep < maxSleep; ++sleep) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + ASSERT_NE(maxSleep, sleep); + + EXPECT_EQ(5u, odomPosesCount); +} + // Run multiple times -INSTANTIATE_TEST_CASE_P(ServerRepeat, DiffDriveTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, DiffDriveTest, ::testing::Range(1, 2)); diff --git a/test/integration/examples_build.cc b/test/integration/examples_build.cc index 9c916b563e..ab1fa1a38b 100644 --- a/test/integration/examples_build.cc +++ b/test/integration/examples_build.cc @@ -174,7 +174,7 @@ TEST_P(ExamplesBuild, Build) } ////////////////////////////////////////////////// -INSTANTIATE_TEST_CASE_P(Plugins, ExamplesBuild, ::testing::Values( +INSTANTIATE_TEST_SUITE_P(Plugins, ExamplesBuild, ::testing::Values( "plugin", "standalone" )); diff --git a/test/integration/follow_actor_system.cc b/test/integration/follow_actor_system.cc index 28ca5191c1..654e578c85 100644 --- a/test/integration/follow_actor_system.cc +++ b/test/integration/follow_actor_system.cc @@ -187,5 +187,5 @@ TEST_P(FollowActorTest, PublishCmd) } // Run multiple times -INSTANTIATE_TEST_CASE_P(ServerRepeat, FollowActorTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, FollowActorTest, ::testing::Range(1, 2)); diff --git a/test/integration/scene_broadcaster_system.cc b/test/integration/scene_broadcaster_system.cc index 8caac85336..b5ae9c0f9c 100644 --- a/test/integration/scene_broadcaster_system.cc +++ b/test/integration/scene_broadcaster_system.cc @@ -564,5 +564,5 @@ TEST_P(SceneBroadcasterTest, StateStatic) } // Run multiple times -INSTANTIATE_TEST_CASE_P(ServerRepeat, SceneBroadcasterTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, SceneBroadcasterTest, ::testing::Range(1, 2)); diff --git a/test/integration/velocity_control_system.cc b/test/integration/velocity_control_system.cc index b3f21ef9dd..02b230c844 100644 --- a/test/integration/velocity_control_system.cc +++ b/test/integration/velocity_control_system.cc @@ -146,5 +146,5 @@ TEST_P(VelocityControlTest, PublishCmd) } // Run multiple times -INSTANTIATE_TEST_CASE_P(ServerRepeat, VelocityControlTest, +INSTANTIATE_TEST_SUITE_P(ServerRepeat, VelocityControlTest, ::testing::Range(1, 2)); diff --git a/test/worlds/diff_drive_custom_frame_id.sdf b/test/worlds/diff_drive_custom_frame_id.sdf new file mode 100644 index 0000000000..073bfc41b8 --- /dev/null +++ b/test/worlds/diff_drive_custom_frame_id.sdf @@ -0,0 +1,245 @@ + + + + + + 0.001 + 1.0 + + + + + + true + 0 0 10 0 0 0 + 1 1 1 1 + 0.5 0.5 0.5 1 + + 1000 + 0.9 + 0.01 + 0.001 + + -0.5 0.1 -0.9 + + + + true + + + + + 0 0 1 + + + + + + + 0 0 1 + 100 100 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + + + 0 0 0.325 0 -0 0 + + + -0.151427 -0 0.175 0 -0 0 + + 1.14395 + + 0.126164 + 0 + 0 + 0.416519 + 0 + 0.481014 + + + + + + 2.01142 1 0.568726 + + + + 0.5 0.5 1.0 1 + 0.5 0.5 1.0 1 + 0.0 0.0 1.0 1 + + + + + + 2.01142 1 0.568726 + + + + + + + 0.554283 0.625029 -0.025 -1.5707 0 0 + + 2 + + 0.145833 + 0 + 0 + 0.145833 + 0 + 0.125 + + + + + + 0.3 + + + + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + + + + + + 0.3 + + + + + + + 0.554282 -0.625029 -0.025 -1.5707 0 0 + + 2 + + 0.145833 + 0 + 0 + 0.145833 + 0 + 0.125 + + + + + + 0.3 + + + + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + + + + + + 0.3 + + + + + + + -0.957138 -0 -0.125 0 -0 0 + + 1 + + 0.1 + 0 + 0 + 0.1 + 0 + 0.1 + + + + + + 0.2 + + + + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + 0.2 0.2 0.2 1 + + + + + + 0.2 + + + + + + + chassis + left_wheel + + 0 0 1 + + -1.79769e+308 + 1.79769e+308 + + + + + + chassis + right_wheel + + 0 0 1 + + -1.79769e+308 + 1.79769e+308 + + + + + + chassis + caster + + + + left_wheel_joint + right_wheel_joint + 1.25 + 0.3 + 1 + 0.5 + odom + base_footprint + + + + + + + + + + + diff --git a/tutorials.md.in b/tutorials.md.in index 6191d0d020..a7f1c5be81 100644 --- a/tutorials.md.in +++ b/tutorials.md.in @@ -22,6 +22,7 @@ Ignition @IGN_DESIGNATION_CAP@ library and how to use the library effectively. * \subpage detachablejoints "Detachable Joints": Creating models that start off rigidly attached and then get detached during simulation. * \subpage triggeredpublisher "Triggered Publisher": Using the TriggeredPublisher system to orchestrate actions in simulation. * \subpage logicalaudiosensor "Logical Audio Sensor": Using the LogicalAudioSensor system to mimic logical audio emission and detection in simulation. +* \subpage videorecorder "Video Recorder": Record videos from the 3D render window. **Migration from Gazebo classic** diff --git a/tutorials/create_system_plugins.md b/tutorials/create_system_plugins.md index 23366aebab..2f03b685ac 100644 --- a/tutorials/create_system_plugins.md +++ b/tutorials/create_system_plugins.md @@ -25,18 +25,19 @@ there are currently three additional available interfaces: with the event manager, as well as modifying entities and components. 2. ISystemPreUpdate 1. Has read-write access to world entities and components. - 2. Executed every iteration with simulation time at (t). - 3. Can be used to modify state before physics runs, for example for applying - control signals or performing network synchronization. -3. ISystemUpdate + 2. This is where systems say what they'd like to happen at time ignition::gazebo::UpdateInfo::simTime. + 3. Can be used to modify state before physics runs, for example for applying control signals or performing network synchronization. +2. ISystemUpdate 1. Has read-write access to world entities and components. - 2. Responsible for propagating time from (t) to (t + dt) for every iteration. - 3. Used for physics simulation step. -4. ISystemPostUpdate + 2. Used for physics simulation step (i.e., simulates what happens at time ignition::gazebo::UpdateInfo::simTime). +3. ISystemPostUpdate 1. Has read-only access to world entities and components. - 2. Executed every iteration with simulation time at (t + dt). - 3. Used to read out results at the end of a simulation step to be used for - sensor or controller updates. + 2. Captures everything that happened at time ignition::gazebo::UpdateInfo::simTime. + 3. Used to read out results at the end of a simulation step to be used for sensor or controller updates. + +It's important to note that ignition::gazebo::UpdateInfo::simTime does not refer to the current time, but the time reached after the `PreUpdate` and `Update` calls have finished. +So, if any of the `*Update` functions are called with simulation paused, time does not advance, which means the time reached after `PreUpdate` and `Update` is the same as the starting time. +This explains why ignition::gazebo::UpdateInfo::simTime is initially 0 if simulation is started paused, while ignition::gazebo::UpdateInfo::simTime is initially ignition::gazebo::UpdateInfo::dt if simulation is started un-paused. Systems that are only used to read the current state of the world (sensors, graphics, and rendering) should implement `ISystemPostUpdate`. diff --git a/tutorials/erb_template.md b/tutorials/erb_template.md index b5cf20a1b0..888d621c4e 100644 --- a/tutorials/erb_template.md +++ b/tutorials/erb_template.md @@ -102,7 +102,7 @@ Each box model also has a different name and pose to ensure they show up as indi %> ``` -[Here](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo3/examples/worlds/shapes_population.sdf.erb) is a complete shapes simulation world example. +[Here](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo4/examples/worlds/shapes_population.sdf.erb) is a complete shapes simulation world example. Instead of simple shapes, you can also use a nested loop to generate 100 actors spaced out evenly in a simulation world. diff --git a/tutorials/files/video_recorder/video_recorder.gif b/tutorials/files/video_recorder/video_recorder.gif new file mode 100644 index 0000000000000000000000000000000000000000..e9e9b28dc9351a56f6f34434f41b1e1d10bf0952 GIT binary patch literal 222842 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 gB)_XA8a{x_M%Mjc+ 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 aK;}Nr2$)4nYTZw*e-&1-BjYfA`~C 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%0D34+>^}tlJo^*SaD)o}HIOa{t>O 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 SnR;Nr$9pLy$!c-q;Qt3LxtI(9 literal 0 HcmV?d00001 diff --git a/tutorials/migrating_ardupilot_plugin.md b/tutorials/migrating_ardupilot_plugin.md index 6b16566c9b..cb499e77f3 100644 --- a/tutorials/migrating_ardupilot_plugin.md +++ b/tutorials/migrating_ardupilot_plugin.md @@ -1,17 +1,15 @@ \page ardupilot -[TOC] +# Case study: migrating the ArduPilot ModelPlugin from Gazebo classic to Ignition Gazebo -# Case study: migrating the ArduPilot ModelPlugin from Classic Gazebo to Ignition Gazebo - -A variety of changes are required when migrating a plugin from Gazebo Classic -("Gazebo") to Ignition Gazebo ("Ignition"). In this tutorial we offer as a case +A variety of changes are required when migrating a plugin from Gazebo classic +to Ignition Gazebo. In this tutorial we offer as a case study the migration of one particular `ModelPlugin`, [ardupilot_gazebo](https://github.com/khancyr/ardupilot_gazebo). We hope that this example provides useful tips to others who are migrating their existing -plugins from Gazebo to Ignition. +plugins from classic to Ignition. -The complete, migrated version of the `ardupilot_gazebo` plugin covered in this tutorial +The complete, migrated version of the `ardupilot_gazebo` plugin covered in this tutorial can be found in [this fork](https://github.com/gerkey/ardupilot_gazebo/tree/ignition). ## Background @@ -24,7 +22,7 @@ documentation](https://ardupilot.org/dev/docs/using-gazebo-simulator-with-sitl.h As context to understand what we're migrating, here's a system diagram for how the ArduPilot Gazebo plugin works is used: - + *UAV icon credit: By Julian Herzog, CC BY 4.0, https://commons.wikimedia.org/w/index.php?curid=60965475* @@ -47,9 +45,9 @@ preserving the rest of the setup. Migration of this plugin involves modifications to multiple parts of the associated code: 1. The plugin header file, `ArduPilotPlugin.hh` -1. The plugin source file, `ArduPilotPlugin.cc` -1. The plugin's CMake build recipe, `CMakeLists.txt` -1. The custom model in which the plugin is used +2. The plugin source file, `ArduPilotPlugin.cc` +3. The plugin's CMake build recipe, `CMakeLists.txt` +4. The custom model in which the plugin is used We'll take them each in turn in the following sections. @@ -57,7 +55,7 @@ We'll take them each in turn in the following sections. ### Headers -The old code includes these Gazebo-related headers: +The old code includes these Gazebo classic headers: ```cpp // OLD @@ -67,7 +65,7 @@ The old code includes these Gazebo-related headers: ``` In the new code, we still need ``, because the underlying [SDFormat -library](http://sdformat.org/) is used by both Gazebo and Ignition. But in place of the `` headers, we'll pull in one from Ignition: +library](http://sdformat.org/) is used by both classic and Ignition. But in place of the `` headers, we'll pull in one from Ignition: ```cpp // NEW @@ -226,10 +224,10 @@ To better understand the ECS pattern as it is used in Ignition, it's helpful to learn about the EntityComponentManager (ECM), which is responsible for managing the ECS graph. A great resource to understand the logic under the hood of the ECM is the `SdfEntityCreator` class -([header](https://github.com/ignitionrobotics/ign-gazebo/blob/master/include/ignition/gazebo/SdfEntityCreator.hh), -[source](https://github.com/ignitionrobotics/ign-gazebo/blob/master/src/SdfEntityCreator.cc)). +([header](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo4/include/ignition/gazebo/SdfEntityCreator.hh), +[source](https://github.com/ignitionrobotics/ign-gazebo/blob/ign-gazebo4/src/SdfEntityCreator.cc)). This class is responsible for mapping the content of an SDF file to the -entities and components that form the graph handled by the ECM. For example, If +entities and components that form the graph handled by the ECM. For example, if you wonder which components can be accessed by default from the plugin, this class is the best entry point. @@ -406,9 +404,6 @@ ignwarn << ... ; ignerr << ... ; ``` -**Suggestion**: Perhaps the old versions could stick around and be deprecated -instead of removed? - ### Plugin interface: Configure() Recall that `Configure()` replaces `Load()`. @@ -434,7 +429,7 @@ Also in the new code we need to make sure of the existence of the specific *components* that we need. In our case, we're going to access the `WorldPose` and `WorldLinearVelocity` components of the *entity* representing one of the UAV model's links. The data in those components will be periodically updated by -the physics *system* (I think). But the physics system will not necessarily +the physics *system*. But the physics system will not necessarily create the components, so before accessing them later in our code, we need to ensure that the components exist: @@ -453,13 +448,6 @@ if(!_ecm.EntityHasComponentType(this->dataPtr->modelLink, components::WorldLinea We'll see this pattern elsewhere in the new code: check for a component's existence, create it if necessary, then proceed with using it. -**Suggestion**: Perhaps we could add syntactic sugar to encapsulate the -check-and-create-if-necessary step? Or alternatively could we guarantee at -startup that systems create all of the components they can use? Either way it -would also be helpful to document which *components* a given *system* will read -from and write to, as they represent the system's API. As present it's easy for -a user to create and interact with a component that no system actually uses. - We also clone the `const sdf::Element` that we've passed so that we can call non-`const` methods on it: @@ -500,10 +488,6 @@ param = controlSDF->Get("vel_i_gain", control.pid.IGain()).first; param = controlSDF->Get("vel_d_gain", control.pid.DGain()).first; ``` -**Suggestion**: Perhaps the old methods could stick around and be deprecated -instead of removed? - - The old code does a bunch of lookups to get a pointer to the IMU sensor. In the new code, we just store the name of the sensors from the user-supplied SDF configuration: @@ -585,9 +569,6 @@ Though it's not part of the regular update loop, we subscribe to the IMU sensor data in `PreUpdate()` because the information that we need for that subscription isn't available when we're in `Configure()`. -**Suggestion**: Perhaps it should be possible to compute topics names for -subscription inside `Configure()`? - That one-time subscription logic looks like this, starting with determination of the right topic name and ending with registering our previously defined `imuCb()` method as the callback to receive new IMU data: @@ -598,34 +579,12 @@ if(!this->dataPtr->imuInitialized) { // Set unconditionally because we're only going to try this once. this->dataPtr->imuInitialized = true; - std::string imuTopicName; - _ecm.Each( - [&](const ignition::gazebo::Entity &_imu_entity, - const ignition::gazebo::components::Imu * /*_imu*/, - const ignition::gazebo::components::Name *_name)->bool - { - if(_name->Data() == this->dataPtr->imuName) - { - // The parent of the imu is imu_link - ignition::gazebo::Entity parent = _ecm.ParentEntity(_imu_entity); - this->dataPtr->modelLink = parent; - if(parent != ignition::gazebo::kNullEntity) - { - // The grandparent of the imu is the quad itself, which is where this plugin is attached - ignition::gazebo::Entity gparent = _ecm.ParentEntity(parent); - if(gparent != ignition::gazebo::kNullEntity) - { - ignition::gazebo::Model gparent_model(gparent); - if(gparent_model.Name(_ecm) == this->dataPtr->modelName) - { - imuTopicName = ignition::gazebo::scopedName(_imu_entity, _ecm) + "/imu"; - igndbg << "Computed IMU topic to be: " << imuTopicName << std::endl; - } - } - } - } - return true; - }); + + auto imuEntity = _ecm.EntityByComponents( + components::Name(this->dataPtr->imuName), + components::Imu(), + components::ParentEntity(this->dataPtr->modelLink)); + auto imuTopicName = _ecm.ComponentData(imuEntity); if(imuTopicName.empty()) { @@ -639,9 +598,6 @@ if(!this->dataPtr->imuInitialized) } ``` -**Suggestion**: There should be an easier way to compute the name of the topic -on which a given sensor's data will be published. - ### Writing to simulation Based on commands received from ArduPilot, new forces are applied to the @@ -663,19 +619,11 @@ exist): ```cpp // NEW -ignition::gazebo::components::JointForceCmd* jfcComp = - _ecm.Component(this->dataPtr->controls[i].joint); -if (jfcComp == nullptr) -{ - jfcComp = _ecm.Component( - _ecm.CreateComponent(this->dataPtr->controls[i].joint, - ignition::gazebo::components::JointForceCmd({0}))); -} -ignition::gazebo::components::JointVelocity* vComp = - _ecm.Component(this->dataPtr->controls[i].joint); -const double vel = vComp->Data()[0]; +const double vel = _ecm.ComponentData( + this->dataPtr->controls[i].joint); // ...do some feedback control math to compute force from vel... -jfcComp->Data()[0] = force; +_ecm.SetComponentData(this->dataPtr->controls[i].joint, + ignition::gazebo::components::JointForceCmd({force})); ``` A similar pattern is used for the case of setting a velocity on a joint; @@ -811,6 +759,7 @@ find_package(ignition-msgs6-all REQUIRED) find_package(ignition-physics3-all REQUIRED) find_package(ignition-sensors4-all REQUIRED) find_package(ignition-transport9-all REQUIRED) + ``` In the old code we need only refer to the build configuration retrieved from the Gazebo package: @@ -837,8 +786,6 @@ include_directories( ${IGNITION-GAZEBO_INCLUDE_DIRS} ${IGNITION-MATH_INCLUDE_DIRS} ${IGNITION-MSGS_INCLUDE_DIRS} - ${IGNITION-PHYSICS_INCLUDE_DIRS} - ${IGNITION-SENSORS_INCLUDE_DIRS} ${IGNITION-TRANSPORT_INCLUDE_DIRS} ) @@ -848,8 +795,6 @@ link_libraries( ${IGNITION-GAZEBO_LIBRARIES} ${IGNITION-MATH_LIBRARIES} ${IGNITION-MSGS_LIBRARIES} - ${IGNITION-PHYSICS_LIBRARIES} - ${IGNITION-SENSORS_LIBRARIES} ${IGNITION-TRANSPORT_LIBRARIES} ) ``` diff --git a/tutorials/video_recorder.md b/tutorials/video_recorder.md new file mode 100644 index 0000000000..50bbef75d9 --- /dev/null +++ b/tutorials/video_recorder.md @@ -0,0 +1,107 @@ +\page videorecorder Video Recorder + +## Using the video recorder plugin + +Ignition Gazebo offers a video recorder tool for recording videos from the 3D +scene. The recorder tool is available as a GUI plugin. To open this plugin, +first launch Ignition Gazebo and select the ellipsis menu on top right +(3 dots menu), and scroll down to find the `Video Recorder` option. Click on the +plugin to open the Video Recorder tool. Alternatively, launch the demo world in +Ignition Gazebo that already has this plugin included in the GUI. + +``` +ign gazebo -v 4 video_record_dbl_pendulum.sdf +``` + +In this plugin, you should see a single button with a video recorder icon. +Clicking on the button gives you the video format options that are available. + +@image html files/video_recorder/video_recorder.png + +Once an option is selected, recording starts immediately as indicated by +a flashing video recorder icon. At anytime that you wish to stop recording, +click on the flashing icon and select `Stop`. A file dialog window should pop up +and let you select the path to save the recorded video in. + +Playback the video you just saved and you should notice that the resolution +of the video is based on the size of your 3D scene window. So if you wish +to record the video in a different size, make sure to configure the GUI +window prior to recording. + +@image html files/video_recorder/video_recorder.gif + + +## Video recorder configurations + +A few video recorder parameters can be specified using GUI configurations, see +the [GUI Configuration](gui_config.html) tutorial for more information. +If you launched Ignition Gazebo with the +`video_record_dbl_pendulum.sdf` demo world, the GUI configurations are embedded +in the world SDF file so you will need to download a copy of the +[sdf file](https://raw.githubusercontent.com/ignitionrobotics/ign-gazebo/ign-gazebo4/examples/worlds/video_record_dbl_pendulum.sdf). +and modify the GUI configuration in that file. On the other hand, if you +launched Ignition Gazebo with a world file that does not have GUI +configurations, you will need to specify the settings in +`$HOME/.ignition/gazebo/gui.config`. + +Recall that videos are recorded from the 3D scene, we will to set the video +configurations in the 3D scene plugin. Here is an example of the +Scene 3D plugin with custom video recorder settings: + +```xml + + + 3D View + false + docked + + + ogre2 + scene + 0.4 0.4 0.4 + 0.8 0.8 0.8 + 6 0 6 0 0.5 3.14 + + + true + true + 4000000 + + + +``` + +Options are: + +* **use_sim_time**: Values are `[true|false]`. Record videos based on sim time, +i.e. each frame encoded into the video will be timestamped using sim time. +For example, if a complex simulation was running at half of real time speed, and +`` is set to true, video playback should ignore delays due +to low Real Time Factor (RTF) and plays back video as if RTF was 1.0. +By default, the value is `false`, which means the videos are recorded based +on real time. + +* **lockstep**: Values are `[true|false]`. Lockstep simulation for video +recording. This forces the GUI to pause and only process a new state update +from the server until the video recorder finishes encoding the current frame. +This ensures that the video recorder does not miss any updates / frames in the +resulting video. This configuration makes more sense when used with +`` set to `true`, in which case it produces smooth videos +with exact timing, i.e. if you record simulation for 1 minute sim time, +the resulting video should be also 1 minute long (+/- 1 second due to encoder +settings). Defaults to `false`. Note: the server publishes states at 60Hz +and the video recorder records at 25 FPS so it also makes sense to update the +Scene Broadcaster system to only publish states at 25Hz. You can do this by +going to the world SDF file, locate the +`ignition::gazebo::systems::SceneBroadcaster` system, and set the +`` parameter: + +```xml + + 25 + +``` + +* **bitrate**: Video encoding bitrate in bps. This affects the quality of the +generated video. The default bitrate is 2Mbps. From 9255e18905157d4abc2ed4d67db5263ea094a43a Mon Sep 17 00:00:00 2001 From: Nate Koenig Date: Fri, 8 Jan 2021 13:26:47 -0800 Subject: [PATCH 19/21] Add support for topic statistics on breadcrumb deployments (#532) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add support for topic statistics on breadcrumb deployments Signed-off-by: Nate Koenig * Require version 9.1 of ignition transport Signed-off-by: Nate Koenig * Move to after mutex Signed-off-by: Nate Koenig Co-authored-by: Nate Koenig Co-authored-by: Carlos Agüero --- CMakeLists.txt | 2 +- src/systems/breadcrumbs/Breadcrumbs.cc | 49 +++++++++++++++++++++++--- src/systems/breadcrumbs/Breadcrumbs.hh | 10 ++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b61f207ab6..719d8b1784 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,7 @@ set(IGN_PLUGIN_VER ${ignition-plugin1_VERSION_MAJOR}) #-------------------------------------- # Find ignition-transport -ign_find_package(ignition-transport9 REQUIRED COMPONENTS log) +ign_find_package(ignition-transport9 REQUIRED COMPONENTS log VERSION 9.1) set(IGN_TRANSPORT_VER ${ignition-transport9_VERSION_MAJOR}) #-------------------------------------- diff --git a/src/systems/breadcrumbs/Breadcrumbs.cc b/src/systems/breadcrumbs/Breadcrumbs.cc index ba98482007..fd740eb10d 100644 --- a/src/systems/breadcrumbs/Breadcrumbs.cc +++ b/src/systems/breadcrumbs/Breadcrumbs.cc @@ -141,13 +141,28 @@ void Breadcrumbs::Configure(const Entity &_entity, topics.push_back("/model/" + this->model.Name(_ecm) + "/breadcrumbs/" + this->modelRoot.ModelByIndex(0)->Name() + "/deploy"); - auto topic = validTopic(topics); + this->topic = validTopic(topics); - this->node.Subscribe(topic, &Breadcrumbs::OnDeploy, this); - this->remainingPub = this->node.Advertise(topic + "/remaining"); + this->topicStatistics = _sdf->Get("topic_statistics", + this->topicStatistics).first; - ignmsg << "Breadcrumbs subscribing to deploy messages on [" << topic << "]" - << std::endl; + // Enable topic statistics when requested. + if (this->topicStatistics) + { + if (!node.EnableStats(this->topic, true)) + { + ignerr << "Unable to enable topic statistics on topic[" + << this->topic << "]." << std::endl; + this->topicStatistics = false; + } + } + + this->node.Subscribe(this->topic, &Breadcrumbs::OnDeploy, this); + this->remainingPub = this->node.Advertise( + this->topic + "/remaining"); + + ignmsg << "Breadcrumbs subscribing to deploy messages on [" + << this->topic << "]" << std::endl; this->creator = std::make_unique(_ecm, _eventMgr); @@ -390,8 +405,32 @@ void Breadcrumbs::OnDeploy(const msgs::Empty &) IGN_PROFILE("Breadcrumbs::PreUpdate"); { std::lock_guard lock(this->pendingCmdsMutex); + this->pendingCmds.push_back(true); } + + // Check topic statistics for dropped messages + if (this->topicStatistics) + { + ignmsg << "Received breadcrumb deployment for " << + this->modelRoot.ModelByIndex(0)->Name() << std::endl; + std::optional stats = + this->node.TopicStats(this->topic); + if (stats) + { + if (stats->DroppedMsgCount() > 0) + { + ignwarn << "Dropped message count of " << stats->DroppedMsgCount() + << " for breadcrumbs on model " + << this->modelRoot.ModelByIndex(0)->Name() << std::endl; + } + } + else + { + ignerr << "Unable to get topic statistics for topic[" + << this->topic << "]." << std::endl; + } + } } IGNITION_ADD_PLUGIN(Breadcrumbs, diff --git a/src/systems/breadcrumbs/Breadcrumbs.hh b/src/systems/breadcrumbs/Breadcrumbs.hh index bb34021344..4800c2d4e4 100644 --- a/src/systems/breadcrumbs/Breadcrumbs.hh +++ b/src/systems/breadcrumbs/Breadcrumbs.hh @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -79,6 +80,9 @@ namespace systems /// Defaults to false. /// ``: This is the model used as a template for deploying /// breadcrumbs. + /// ``: If true, then topic statistics are enabled on + /// `` and error messages will be generated when messages are + /// dropped. Default to false. class IGNITION_GAZEBO_VISIBLE Breadcrumbs : public System, public ISystemConfigure, @@ -163,6 +167,12 @@ namespace systems /// \brief Publishes remaining deployments. public: transport::Node::Publisher remainingPub; + + /// \brief True when topic statistics are enabled. + public: bool topicStatistics{false}; + + /// \brief Name of the deploy topic. + public: std::string topic; }; } } From eded758a0d1fa1afd8f78625a70d357390c79c24 Mon Sep 17 00:00:00 2001 From: Steve Peters Date: Mon, 11 Jan 2021 10:48:06 -0800 Subject: [PATCH 20/21] Improve ign tool support on macOS (#477) * Enable ign test on macOS - Set environment variables in cmake - Find ign binary location - Try to find brew ruby location to workaround SIP * Suggest fixes for ign gazebo failures on macOS Recommend using brew ruby and ensuring that colcon setup scripts have been sourced. * Exit `ign gazebo` early on macOS unless -s is used Signed-off-by: Steve Peters --- CMakeLists.txt | 6 ++++++ src/CMakeLists.txt | 30 ++++++++++++++++++++++++++++++ src/cmd/cmdgazebo.rb.in | 23 +++++++++++++++++++++++ src/ign_TEST.cc | 22 ++-------------------- 4 files changed, 61 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 719d8b1784..6d2934362e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,12 @@ set(IGN_RENDERING_VER ${ignition-rendering4_VERSION_MAJOR}) ign_find_package(ignition-math6 REQUIRED COMPONENTS eigen3 VERSION 6.6) set(IGN_MATH_VER ${ignition-math6_VERSION_MAJOR}) +#-------------------------------------- +# Find ignition-tools +ign_find_package(ignition-tools + REQUIRED + PKGCONFIG "ignition-tools") + #-------------------------------------- # Find protobuf set(REQ_PROTOBUF_VER 3) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1c029e2900..9cff6aa9b0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -131,6 +131,36 @@ ign_build_tests(TYPE UNIT ignition-gazebo${PROJECT_VERSION_MAJOR} ) +if(TARGET UNIT_ign_TEST) + + # Running `ign gazebo` on macOS has problems when run with /usr/bin/ruby + # due to System Integrity Protection (SIP). Try to find ruby from + # homebrew as a workaround. + if (APPLE) + find_program(BREW_RUBY ruby HINTS /usr/local/opt/ruby/bin) + endif() + + add_dependencies(UNIT_ign_TEST + ${ign_lib_target} + TestModelSystem + TestSensorSystem + TestWorldSystem + ) + + target_compile_definitions(UNIT_ign_TEST PRIVATE + "BREW_RUBY=\"${BREW_RUBY} \"") + + target_compile_definitions(UNIT_ign_TEST PRIVATE + "IGN_PATH=\"${IGNITION-TOOLS_BINARY_DIRS}\"") + + set(_env_vars) + list(APPEND _env_vars "IGN_CONFIG_PATH=${CMAKE_BINARY_DIR}/test/conf") + list(APPEND _env_vars "IGN_GAZEBO_SYSTEM_PLUGIN_PATH=$") + + set_tests_properties(UNIT_ign_TEST PROPERTIES + ENVIRONMENT "${_env_vars}") +endif() + if(NOT WIN32) add_subdirectory(cmd) endif() diff --git a/src/cmd/cmdgazebo.rb.in b/src/cmd/cmdgazebo.rb.in index 594e360763..079bfeae19 100755 --- a/src/cmd/cmdgazebo.rb.in +++ b/src/cmd/cmdgazebo.rb.in @@ -337,6 +337,17 @@ class Cmd Importer.dlload plugin rescue DLError => e puts "Library error for [#{plugin}]: #{e.to_s}" + if plugin.end_with? ".dylib" + puts " +If this script was executed with /usr/bin/ruby, this error may be caused by +macOS System Integrity Protection. One workaround is to use a different +version of ruby, for example: + brew install ruby +and add the following line to your shell profile: + export PATH=/usr/local/opt/ruby/bin:$PATH +If you are using a colcon workspace, please ensure that the setup script +has properly set the DYLD_LIBRARY_PATH environment variables." + end exit(-1) end @@ -435,6 +446,12 @@ class Cmd # and gui. if options['server'] == 0 && options['gui'] == 0 + if plugin.end_with? ".dylib" + puts "`ign gazebo` currently only works with the -s argument on macOS. +See https://github.com/ignitionrobotics/ign-gazebo/issues/44 for more info." + exit(-1) + end + serverPid = Process.fork do ENV['RMT_PORT'] = '1500' Process.setpgid(0, 0) @@ -484,6 +501,12 @@ class Cmd options['file'], options['record-topics'].join(':')) # Otherwise run the gui else options['gui'] + if plugin.end_with? ".dylib" + puts "`ign gazebo` currently only works with the -s argument on macOS. +See https://github.com/ignitionrobotics/ign-gazebo/issues/44 for more info." + exit(-1) + end + ENV['RMT_PORT'] = '1501' Importer.runGui(options['gui_config']) end diff --git a/src/ign_TEST.cc b/src/ign_TEST.cc index c5d0fcdc7f..8bb0986e9d 100644 --- a/src/ign_TEST.cc +++ b/src/ign_TEST.cc @@ -26,12 +26,8 @@ static const std::string kBinPath(PROJECT_BINARY_PATH); -// Command line not working on OSX, see -// https://github.com/ignitionrobotics/ign-gazebo/issues/25/ -#ifndef __APPLE__ static const std::string kIgnCommand( - "IGN_GAZEBO_SYSTEM_PLUGIN_PATH=" + kBinPath + "/lib LD_LIBRARY_PATH=" + - kBinPath + "/lib:/usr/local/lib:${LD_LIBRARY_PATH} ign gazebo -s "); + std::string(BREW_RUBY) + std::string(IGN_PATH) + "/ign gazebo -s "); ///////////////////////////////////////////////// std::string customExecStr(std::string _cmd) @@ -90,8 +86,7 @@ TEST(CmdLine, Server) } ///////////////////////////////////////////////// -// Not supported on Mac's command line tool -TEST(CmdLine, IGN_UTILS_TEST_DISABLED_ON_MAC(CachedFuelWorld)) +TEST(CmdLine, CachedFuelWorld) { std::string projectPath = std::string(PROJECT_SOURCE_PATH) + "/test/worlds"; setenv("IGN_FUEL_CACHE_PATH", projectPath.c_str(), true); @@ -164,16 +159,3 @@ TEST(CmdLine, ResourcePath) EXPECT_EQ(output.find("Unable to find file plugins.sdf"), std::string::npos) << output; } -#endif - -///////////////////////////////////////////////// -/// Main -int main(int _argc, char **_argv) -{ - // Set IGN_CONFIG_PATH to the directory where the .yaml configuration files - // is located. - setenv("IGN_CONFIG_PATH", IGN_CONFIG_PATH, 1); - - ::testing::InitGoogleTest(&_argc, _argv); - return RUN_ALL_TESTS(); -} From 08252fd5da9bdabad325fc8238a5a79cf2418d15 Mon Sep 17 00:00:00 2001 From: Jaldert Rombouts Date: Tue, 12 Jan 2021 12:23:20 +0000 Subject: [PATCH 21/21] [FIX] Handle multiple logical cameras (#539) Extend test to have two logical cameras observing the same box. Signed-off-by: Jaldert Rombouts --- src/systems/logical_camera/LogicalCamera.cc | 4 +- test/integration/logical_camera_system.cc | 121 ++++++++++++++------ test/worlds/logical_camera_sensor.sdf | 36 +++++- 3 files changed, 125 insertions(+), 36 deletions(-) diff --git a/src/systems/logical_camera/LogicalCamera.cc b/src/systems/logical_camera/LogicalCamera.cc index 76deeef860..9a16fcf40c 100644 --- a/src/systems/logical_camera/LogicalCamera.cc +++ b/src/systems/logical_camera/LogicalCamera.cc @@ -202,7 +202,9 @@ void LogicalCameraPrivate::UpdateLogicalCameras( { const math::Pose3d &worldPose = _worldPose->Data(); it->second->SetPose(worldPose); - it->second->SetModelPoses(std::move(modelPoses)); + // Make a copy of modelPoses s.t. SetModelPoses can take ownership + auto modelPoses_ = modelPoses; + it->second->SetModelPoses(std::move(modelPoses_)); } else { diff --git a/test/integration/logical_camera_system.cc b/test/integration/logical_camera_system.cc index 2dc0241419..94e4763bb6 100644 --- a/test/integration/logical_camera_system.cc +++ b/test/integration/logical_camera_system.cc @@ -49,18 +49,28 @@ class LogicalCameraTest : public ::testing::Test }; std::mutex mutex; -std::vector logicalCameraMsgs; +std::vector logicalCamera1Msgs; +std::vector logicalCamera2Msgs; ///////////////////////////////////////////////// -void logicalCameraCb(const msgs::LogicalCameraImage &_msg) +void logicalCamera1Cb(const msgs::LogicalCameraImage &_msg) { mutex.lock(); - logicalCameraMsgs.push_back(_msg); + logicalCamera1Msgs.push_back(_msg); mutex.unlock(); } ///////////////////////////////////////////////// -// The test checks the logical camera readings when it faces a box +void logicalCamera2Cb(const msgs::LogicalCameraImage &_msg) +{ + mutex.lock(); + logicalCamera2Msgs.push_back(_msg); + mutex.unlock(); +} + +///////////////////////////////////////////////// +// This test checks that both logical cameras in the world can see a box +// at the correct relative pose. TEST_F(LogicalCameraTest, LogicalCameraBox) { // Start server @@ -73,14 +83,18 @@ TEST_F(LogicalCameraTest, LogicalCameraBox) EXPECT_FALSE(server.Running()); EXPECT_FALSE(*server.Running(0)); - const std::string sensorName = "logical_camera"; + const std::string sensorName1 = "logical_camera-1"; + auto topic1 = "world/logical_camera_sensor/model/logical_camera-1/link/" + "logical_camera_link/sensor/logical_camera-1/logical_camera"; - auto topic = "world/logical_camera_sensor/model/logical_camera/link/" - "logical_camera_link/sensor/logical_camera/logical_camera"; + const std::string sensorName2 = "logical_camera-2"; + auto topic2 = "world/logical_camera_sensor/model/logical_camera-2/link/" + "logical_camera_link/sensor/logical_camera-2/logical_camera"; - bool updateChecked{false}; + bool update1Checked{false}; + bool update2Checked{false}; - // Create a system that checks sensor topic + // Create a system that checks sensor topics test::Relay testSystem; testSystem.OnPostUpdate([&](const gazebo::UpdateInfo &, const gazebo::EntityComponentManager &_ecm) @@ -90,20 +104,40 @@ TEST_F(LogicalCameraTest, LogicalCameraBox) const components::LogicalCamera *, const components::Name *_name) -> bool { - EXPECT_EQ(_name->Data(), sensorName); - - auto sensorComp = _ecm.Component(_entity); - EXPECT_NE(nullptr, sensorComp); - - auto topicComp = _ecm.Component(_entity); - EXPECT_NE(nullptr, topicComp); - if (topicComp) + // Sensor 1 + if (_name->Data() == sensorName1) { - EXPECT_EQ(topic, topicComp->Data()); + auto sensorComp = _ecm.Component(_entity); + EXPECT_NE(nullptr, sensorComp); + + auto topicComp = + _ecm.Component(_entity); + EXPECT_NE(nullptr, topicComp); + if (topicComp) { + EXPECT_EQ(topic1, topicComp->Data()); + } + update1Checked = true; + } + // Sensor 2 + else if (_name->Data() == sensorName2) + { + auto sensorComp = _ecm.Component(_entity); + EXPECT_NE(nullptr, sensorComp); + + auto topicComp = + _ecm.Component(_entity); + EXPECT_NE(nullptr, topicComp); + if (topicComp) { + EXPECT_EQ(topic2, topicComp->Data()); + } + update2Checked = true; + } + else + { + // We should not hit this, as it implies an unknown + // sensor name. + EXPECT_TRUE(false) << "Unknown sensor name."; } - - updateChecked = true; - return true; }); }); @@ -113,27 +147,48 @@ TEST_F(LogicalCameraTest, LogicalCameraBox) // subscribe to logical camera topic transport::Node node; node.Subscribe(std::string("/world/logical_camera_sensor/") + - "model/logical_camera/link/logical_camera_link" + - "/sensor/logical_camera/logical_camera", &logicalCameraCb); + "model/logical_camera-1/link/logical_camera_link" + + "/sensor/logical_camera-1/logical_camera", &logicalCamera1Cb); + + node.Subscribe(std::string("/world/logical_camera_sensor/") + + "model/logical_camera-2/link/logical_camera_link" + + "/sensor/logical_camera-2/logical_camera", &logicalCamera2Cb); // Run server and verify that we are receiving messages size_t iters100 = 100u; server.Run(true, iters100, false); - EXPECT_TRUE(updateChecked); + EXPECT_TRUE(update1Checked); + EXPECT_TRUE(update2Checked); mutex.lock(); - EXPECT_GT(logicalCameraMsgs.size(), 0u); + EXPECT_GT(logicalCamera1Msgs.size(), 0u); mutex.unlock(); - // Sensor should see box + mutex.lock(); + EXPECT_GT(logicalCamera2Msgs.size(), 0u); + mutex.unlock(); + + // Sensor 1 should see box std::string boxName = "box"; math::Pose3d boxPose(1, 0, 0.5, 0, 0, 0); - math::Pose3d sensorPose(0.05, 0.05, 0.55, 0, 0, 0); + math::Pose3d sensor1Pose(0.05, 0.05, 0.55, 0, 0, 0); mutex.lock(); - ignition::msgs::LogicalCameraImage img = logicalCameraMsgs.back(); - EXPECT_EQ(sensorPose, ignition::msgs::Convert(img.pose())); - EXPECT_EQ(1, img.model().size()); - EXPECT_EQ(boxName, img.model(0).name()); - ignition::math::Pose3d boxPoseCameraFrame = boxPose - sensorPose; - EXPECT_EQ(boxPoseCameraFrame, ignition::msgs::Convert(img.model(0).pose())); + ignition::msgs::LogicalCameraImage img1 = logicalCamera1Msgs.back(); + EXPECT_EQ(sensor1Pose, ignition::msgs::Convert(img1.pose())); + EXPECT_EQ(1, img1.model().size()); + EXPECT_EQ(boxName, img1.model(0).name()); + ignition::math::Pose3d boxPoseCamera1Frame = boxPose - sensor1Pose; + EXPECT_EQ(boxPoseCamera1Frame, ignition::msgs::Convert(img1.model(0).pose())); mutex.unlock(); + + // Sensor 2 should see box too - note different sensor pose. + math::Pose3d sensor2Pose(0.05, -0.45, 0.55, 0, 0, 0); + mutex.lock(); + ignition::msgs::LogicalCameraImage img2 = logicalCamera2Msgs.back(); + EXPECT_EQ(sensor2Pose, ignition::msgs::Convert(img2.pose())); + EXPECT_EQ(1, img2.model().size()); + EXPECT_EQ(boxName, img2.model(0).name()); + ignition::math::Pose3d boxPoseCamera2Frame = boxPose - sensor2Pose; + EXPECT_EQ(boxPoseCamera2Frame, ignition::msgs::Convert(img2.model(0).pose())); + mutex.unlock(); + } diff --git a/test/worlds/logical_camera_sensor.sdf b/test/worlds/logical_camera_sensor.sdf index 6ca45a21d0..fce03dfd7b 100644 --- a/test/worlds/logical_camera_sensor.sdf +++ b/test/worlds/logical_camera_sensor.sdf @@ -96,7 +96,7 @@ - + true 0 0 0.5 0 0 0.0 @@ -115,7 +115,39 @@ - " + " + 10 + + 0.55 + 5 + 1.04719755 + 1.778 + + 1 + true + + + + + true + 0 -0.5 0.5 0 0 0.0 + + 0.05 0.05 0.05 0 0 0 + + + + 0.1 0.1 0.1 + + + + + + + 0.1 0.1 0.1 + + + + " 10 0.55