Merge branch 'master' of https://github.com/assimp/assimp into fix/collada_parser_sid
commit
079b7deb33
|
@ -0,0 +1,16 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Use this section to tell people about which versions of your project are
|
||||||
|
currently being supported with security updates.
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 5.2.4 | :white_check_mark: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you have found any security vulnerability you can contact us via
|
||||||
|
kim.kulling@googlemail.com
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2022, assimp team
|
Copyright (c) 2006-2022, assimp team
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -87,11 +86,6 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element &element, const std::s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
AnimationCurve::~AnimationCurve() {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name,
|
AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name,
|
||||||
const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
|
const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
|
||||||
|
@ -147,11 +141,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, cons
|
||||||
props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
|
props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
AnimationCurveNode::~AnimationCurveNode() {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
const AnimationCurveMap &AnimationCurveNode::Curves() const {
|
const AnimationCurveMap &AnimationCurveNode::Curves() const {
|
||||||
if (curves.empty()) {
|
if (curves.empty()) {
|
||||||
|
@ -193,11 +182,6 @@ AnimationLayer::AnimationLayer(uint64_t id, const Element &element, const std::s
|
||||||
props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
|
props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
AnimationLayer::~AnimationLayer() {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/,
|
AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/,
|
||||||
size_t whitelist_size /*= 0*/) const {
|
size_t whitelist_size /*= 0*/) const {
|
||||||
|
@ -279,11 +263,6 @@ AnimationStack::AnimationStack(uint64_t id, const Element &element, const std::s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
AnimationStack::~AnimationStack() {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace FBX
|
} // namespace FBX
|
||||||
} // namespace Assimp
|
} // namespace Assimp
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
|
||||||
const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
|
static constexpr size_t NumNullRecords = 25;
|
||||||
|
const char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
|
||||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
|
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
|
||||||
}; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)
|
}; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2022, assimp team
|
Copyright (c) 2006-2022, assimp team
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
|
|
@ -65,12 +65,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <tuple>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
@ -187,8 +184,7 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
|
||||||
|
|
||||||
/// This struct manages nodes which may or may not end up in the node hierarchy.
|
/// This struct manages nodes which may or may not end up in the node hierarchy.
|
||||||
/// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
|
/// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
|
||||||
struct FBXConverter::PotentialNode
|
struct FBXConverter::PotentialNode {
|
||||||
{
|
|
||||||
PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
|
PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
|
||||||
PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
|
PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
|
||||||
aiNode* operator->() { return mNode; }
|
aiNode* operator->() { return mNode; }
|
||||||
|
@ -231,7 +227,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
|
||||||
if (nullptr != model) {
|
if (nullptr != model) {
|
||||||
nodes_chain.clear();
|
nodes_chain.clear();
|
||||||
post_nodes_chain.clear();
|
post_nodes_chain.clear();
|
||||||
|
aiMatrix4x4 new_abs_transform = parent->mTransformation;
|
||||||
std::string node_name = FixNodeName(model->Name());
|
std::string node_name = FixNodeName(model->Name());
|
||||||
// even though there is only a single input node, the design of
|
// even though there is only a single input node, the design of
|
||||||
// assimp (or rather: the complicated transformation chain that
|
// assimp (or rather: the complicated transformation chain that
|
||||||
|
@ -268,7 +264,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// attach geometry
|
// attach geometry
|
||||||
ConvertModel(*model, nodes_chain.back().mNode, root_node);
|
ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform);
|
||||||
|
|
||||||
// check if there will be any child nodes
|
// check if there will be any child nodes
|
||||||
const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
|
const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
|
||||||
|
@ -447,7 +443,7 @@ void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueNam
|
||||||
auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
|
auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
|
||||||
unsigned int &i = it_pair.first->second;
|
unsigned int &i = it_pair.first->second;
|
||||||
while (!it_pair.second) {
|
while (!it_pair.second) {
|
||||||
i++;
|
++i;
|
||||||
std::ostringstream ext;
|
std::ostringstream ext;
|
||||||
ext << name << std::setfill('0') << std::setw(3) << i;
|
ext << name << std::setfill('0') << std::setw(3) << i;
|
||||||
uniqueName = ext.str();
|
uniqueName = ext.str();
|
||||||
|
@ -646,9 +642,8 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
|
||||||
|
|
||||||
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
|
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
|
||||||
const PropertyTable &props = model.Props();
|
const PropertyTable &props = model.Props();
|
||||||
bool ok;
|
|
||||||
|
|
||||||
const float zero_epsilon = ai_epsilon;
|
const auto zero_epsilon = ai_epsilon;
|
||||||
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
|
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
|
||||||
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
|
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
|
||||||
const TransformationComp comp = static_cast<TransformationComp>(i);
|
const TransformationComp comp = static_cast<TransformationComp>(i);
|
||||||
|
@ -660,6 +655,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
|
||||||
|
|
||||||
bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
|
bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
|
const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
|
||||||
if (ok && scale_compare) {
|
if (ok && scale_compare) {
|
||||||
if ((v - all_ones).SquareLength() > zero_epsilon) {
|
if ((v - all_ones).SquareLength() > zero_epsilon) {
|
||||||
|
@ -894,18 +890,17 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node) {
|
void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
|
||||||
const std::vector<const Geometry *> &geos = model.GetGeometry();
|
const std::vector<const Geometry *> &geos = model.GetGeometry();
|
||||||
|
|
||||||
std::vector<unsigned int> meshes;
|
std::vector<unsigned int> meshes;
|
||||||
meshes.reserve(geos.size());
|
meshes.reserve(geos.size());
|
||||||
|
|
||||||
for (const Geometry *geo : geos) {
|
for (const Geometry *geo : geos) {
|
||||||
|
|
||||||
const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo);
|
const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo);
|
||||||
const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo);
|
const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo);
|
||||||
if (mesh) {
|
if (mesh) {
|
||||||
const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node);
|
const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node, absolute_transform);
|
||||||
std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
|
std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
|
||||||
} else if (line) {
|
} else if (line) {
|
||||||
const std::vector<unsigned int> &indices = ConvertLine(*line, root_node);
|
const std::vector<unsigned int> &indices = ConvertLine(*line, root_node);
|
||||||
|
@ -926,7 +921,7 @@ void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned int>
|
std::vector<unsigned int>
|
||||||
FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node) {
|
FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
|
||||||
std::vector<unsigned int> temp;
|
std::vector<unsigned int> temp;
|
||||||
|
|
||||||
MeshMap::const_iterator it = meshes_converted.find(&mesh);
|
MeshMap::const_iterator it = meshes_converted.find(&mesh);
|
||||||
|
@ -949,13 +944,13 @@ FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *
|
||||||
const MatIndexArray::value_type base = mindices[0];
|
const MatIndexArray::value_type base = mindices[0];
|
||||||
for (MatIndexArray::value_type index : mindices) {
|
for (MatIndexArray::value_type index : mindices) {
|
||||||
if (index != base) {
|
if (index != base) {
|
||||||
return ConvertMeshMultiMaterial(mesh, model, parent, root_node);
|
return ConvertMeshMultiMaterial(mesh, model, absolute_transform, parent, root_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// faster code-path, just copy the data
|
// faster code-path, just copy the data
|
||||||
temp.push_back(ConvertMeshSingleMaterial(mesh, model, parent, root_node));
|
temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1023,7 +1018,35 @@ aiMesh *FBXConverter::SetupEmptyMesh(const Geometry &mesh, aiNode *parent) {
|
||||||
return out_mesh;
|
return out_mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
|
static aiSkeleton *createAiSkeleton(SkeletonBoneContainer &sbc) {
|
||||||
|
if (sbc.MeshArray.empty() || sbc.SkeletonBoneToMeshLookup.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
aiSkeleton *skeleton = new aiSkeleton;
|
||||||
|
for (auto *mesh : sbc.MeshArray) {
|
||||||
|
auto it = sbc.SkeletonBoneToMeshLookup.find(mesh);
|
||||||
|
if (it == sbc.SkeletonBoneToMeshLookup.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SkeletonBoneArray *ba = it->second;
|
||||||
|
if (ba == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
skeleton->mNumBones = static_cast<unsigned int>(ba->size());
|
||||||
|
skeleton->mBones = new aiSkeletonBone*[skeleton->mNumBones];
|
||||||
|
size_t index = 0;
|
||||||
|
for (auto bone : (* ba)) {
|
||||||
|
skeleton->mBones[index] = bone;
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
|
||||||
aiNode *parent, aiNode *) {
|
aiNode *parent, aiNode *) {
|
||||||
const MatIndexArray &mindices = mesh.GetMaterialIndices();
|
const MatIndexArray &mindices = mesh.GetMaterialIndices();
|
||||||
aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
|
aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
|
||||||
|
@ -1142,8 +1165,15 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
|
||||||
ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
|
ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) {
|
if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && !doc.Settings().useSkeleton) {
|
||||||
ConvertWeights(out_mesh, mesh, parent, NO_MATERIAL_SEPARATION, nullptr);
|
ConvertWeights(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr);
|
||||||
|
} else if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && doc.Settings().useSkeleton) {
|
||||||
|
SkeletonBoneContainer sbc;
|
||||||
|
ConvertWeightsToSkeleton(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr, sbc);
|
||||||
|
aiSkeleton *skeleton = createAiSkeleton(sbc);
|
||||||
|
if (skeleton != nullptr) {
|
||||||
|
mSkeletons.emplace_back(skeleton);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<aiAnimMesh *> animMeshes;
|
std::vector<aiAnimMesh *> animMeshes;
|
||||||
|
@ -1190,7 +1220,7 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned int>
|
std::vector<unsigned int>
|
||||||
FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent,
|
FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, aiNode *parent,
|
||||||
aiNode *root_node) {
|
aiNode *root_node) {
|
||||||
const MatIndexArray &mindices = mesh.GetMaterialIndices();
|
const MatIndexArray &mindices = mesh.GetMaterialIndices();
|
||||||
ai_assert(mindices.size());
|
ai_assert(mindices.size());
|
||||||
|
@ -1201,7 +1231,7 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
|
||||||
for (MatIndexArray::value_type index : mindices) {
|
for (MatIndexArray::value_type index : mindices) {
|
||||||
if (had.find(index) == had.end()) {
|
if (had.find(index) == had.end()) {
|
||||||
|
|
||||||
indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node));
|
indices.push_back(ConvertMeshMultiMaterial(mesh, model, absolute_transform, index, parent, root_node));
|
||||||
had.insert(index);
|
had.insert(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1209,9 +1239,8 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
|
||||||
return indices;
|
return indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model,
|
unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
|
||||||
MatIndexArray::value_type index,
|
MatIndexArray::value_type index, aiNode *parent, aiNode *) {
|
||||||
aiNode *parent, aiNode *) {
|
|
||||||
aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
|
aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
|
||||||
|
|
||||||
const MatIndexArray &mindices = mesh.GetMaterialIndices();
|
const MatIndexArray &mindices = mesh.GetMaterialIndices();
|
||||||
|
@ -1374,7 +1403,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
|
||||||
ConvertMaterialForMesh(out_mesh, model, mesh, index);
|
ConvertMaterialForMesh(out_mesh, model, mesh, index);
|
||||||
|
|
||||||
if (process_weights) {
|
if (process_weights) {
|
||||||
ConvertWeights(out_mesh, mesh, parent, index, &reverseMapping);
|
ConvertWeights(out_mesh, mesh, absolute_transform, parent, index, &reverseMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<aiAnimMesh *> animMeshes;
|
std::vector<aiAnimMesh *> animMeshes;
|
||||||
|
@ -1424,19 +1453,47 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
|
||||||
return static_cast<unsigned int>(mMeshes.size() - 1);
|
return static_cast<unsigned int>(mMeshes.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
|
static void copyBoneToSkeletonBone(aiMesh *mesh, aiBone *bone, aiSkeletonBone *skeletonBone ) {
|
||||||
|
skeletonBone->mNumnWeights = bone->mNumWeights;
|
||||||
|
skeletonBone->mWeights = bone->mWeights;
|
||||||
|
skeletonBone->mOffsetMatrix = bone->mOffsetMatrix;
|
||||||
|
skeletonBone->mMeshId = mesh;
|
||||||
|
skeletonBone->mNode = bone->mNode;
|
||||||
|
skeletonBone->mParent = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBXConverter::ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent, unsigned int materialIndex,
|
||||||
|
std::vector<unsigned int> *outputVertStartIndices, SkeletonBoneContainer &skeletonContainer) {
|
||||||
|
|
||||||
|
if (skeletonContainer.SkeletonBoneToMeshLookup.find(out) != skeletonContainer.SkeletonBoneToMeshLookup.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConvertWeights(out, geo, absolute_transform, parent, materialIndex, outputVertStartIndices);
|
||||||
|
skeletonContainer.MeshArray.emplace_back(out);
|
||||||
|
SkeletonBoneArray *ba = new SkeletonBoneArray;
|
||||||
|
for (size_t i = 0; i < out->mNumBones; ++i) {
|
||||||
|
aiBone *bone = out->mBones[i];
|
||||||
|
if (bone == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
aiSkeletonBone *skeletonBone = new aiSkeletonBone;
|
||||||
|
copyBoneToSkeletonBone(out, bone, skeletonBone);
|
||||||
|
ba->emplace_back(skeletonBone);
|
||||||
|
}
|
||||||
|
skeletonContainer.SkeletonBoneToMeshLookup[out] = ba;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
|
||||||
aiNode *parent, unsigned int materialIndex,
|
aiNode *parent, unsigned int materialIndex,
|
||||||
std::vector<unsigned int> *outputVertStartIndices) {
|
std::vector<unsigned int> *outputVertStartIndices) {
|
||||||
ai_assert(geo.DeformerSkin());
|
ai_assert(geo.DeformerSkin());
|
||||||
|
|
||||||
std::vector<size_t> out_indices;
|
std::vector<size_t> out_indices, index_out_indices, count_out_indices;
|
||||||
std::vector<size_t> index_out_indices;
|
|
||||||
std::vector<size_t> count_out_indices;
|
|
||||||
|
|
||||||
const Skin &sk = *geo.DeformerSkin();
|
const Skin &sk = *geo.DeformerSkin();
|
||||||
|
|
||||||
std::vector<aiBone *> bones;
|
std::vector<aiBone*> bones;
|
||||||
|
|
||||||
const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
|
const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
|
||||||
ai_assert(no_mat_check || outputVertStartIndices);
|
ai_assert(no_mat_check || outputVertStartIndices);
|
||||||
|
|
||||||
|
@ -1496,7 +1553,7 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
|
||||||
// XXX this could be heavily simplified by collecting the bone
|
// XXX this could be heavily simplified by collecting the bone
|
||||||
// data in a single step.
|
// data in a single step.
|
||||||
ConvertCluster(bones, cluster, out_indices, index_out_indices,
|
ConvertCluster(bones, cluster, out_indices, index_out_indices,
|
||||||
count_out_indices, parent);
|
count_out_indices, absolute_transform, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
bone_map.clear();
|
bone_map.clear();
|
||||||
|
@ -1509,25 +1566,20 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
|
||||||
out->mBones = nullptr;
|
out->mBones = nullptr;
|
||||||
out->mNumBones = 0;
|
out->mNumBones = 0;
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
out->mBones = new aiBone *[bones.size()]();
|
|
||||||
out->mNumBones = static_cast<unsigned int>(bones.size());
|
|
||||||
|
|
||||||
std::swap_ranges(bones.begin(), bones.end(), out->mBones);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out->mBones = new aiBone *[bones.size()]();
|
||||||
|
out->mNumBones = static_cast<unsigned int>(bones.size());
|
||||||
|
std::swap_ranges(bones.begin(), bones.end(), out->mBones);
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiNode *GetNodeByName(aiNode *current_node) {
|
void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const Cluster *cluster,
|
||||||
aiNode *iter = current_node;
|
|
||||||
//printf("Child count: %d", iter->mNumChildren);
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
|
||||||
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
|
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
|
||||||
std::vector<size_t> &count_out_indices, aiNode *) {
|
std::vector<size_t> &count_out_indices, const aiMatrix4x4 & /* absolute_transform*/,
|
||||||
ai_assert(cl); // make sure cluster valid
|
aiNode *) {
|
||||||
std::string deformer_name = cl->TargetNode()->Name();
|
ai_assert(cluster != nullptr); // make sure cluster valid
|
||||||
|
|
||||||
|
std::string deformer_name = cluster->TargetNode()->Name();
|
||||||
aiString bone_name = aiString(FixNodeName(deformer_name));
|
aiString bone_name = aiString(FixNodeName(deformer_name));
|
||||||
|
|
||||||
aiBone *bone = nullptr;
|
aiBone *bone = nullptr;
|
||||||
|
@ -1540,10 +1592,10 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
|
||||||
bone = new aiBone();
|
bone = new aiBone();
|
||||||
bone->mName = bone_name;
|
bone->mName = bone_name;
|
||||||
|
|
||||||
bone->mOffsetMatrix = cl->Transform();
|
bone->mOffsetMatrix = cluster->Transform();
|
||||||
// store local transform link for post processing
|
// store local transform link for post processing
|
||||||
/*
|
/*
|
||||||
bone->mOffsetMatrix = cl->TransformLink();
|
bone->mOffsetMatrix = cluster->TransformLink();
|
||||||
bone->mOffsetMatrix.Inverse();
|
bone->mOffsetMatrix.Inverse();
|
||||||
|
|
||||||
aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
|
aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
|
||||||
|
@ -1560,7 +1612,7 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
|
||||||
cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
|
cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
|
||||||
|
|
||||||
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
||||||
const WeightArray &weights = cl->GetWeights();
|
const WeightArray &weights = cluster->GetWeights();
|
||||||
|
|
||||||
const size_t c = index_out_indices.size();
|
const size_t c = index_out_indices.size();
|
||||||
for (size_t i = 0; i < c; ++i) {
|
for (size_t i = 0; i < c; ++i) {
|
||||||
|
@ -2151,7 +2203,7 @@ void FBXConverter::SetShadingPropertiesCommon(aiMaterial *out_mat, const Propert
|
||||||
if (ok) {
|
if (ok) {
|
||||||
out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS);
|
out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS);
|
||||||
// Match Blender behavior to extract roughness when only shininess is present
|
// Match Blender behavior to extract roughness when only shininess is present
|
||||||
const float roughness = 1.0 - (sqrt(ShininessExponent) / 10.0);
|
const float roughness = 1.0f - (sqrt(ShininessExponent) / 10.0f);
|
||||||
out_mat->AddProperty(&roughness, 1, AI_MATKEY_ROUGHNESS_FACTOR);
|
out_mat->AddProperty(&roughness, 1, AI_MATKEY_ROUGHNESS_FACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2605,7 +2657,7 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
|
||||||
meshMorphAnim->mNumKeys = numKeys;
|
meshMorphAnim->mNumKeys = numKeys;
|
||||||
meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys];
|
meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys];
|
||||||
unsigned int j = 0;
|
unsigned int j = 0;
|
||||||
for (auto animIt : *animData) {
|
for (auto &animIt : *animData) {
|
||||||
morphKeyData *keyData = animIt.second;
|
morphKeyData *keyData = animIt.second;
|
||||||
unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size());
|
unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size());
|
||||||
meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
|
meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
|
||||||
|
@ -3180,7 +3232,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
const float zero_epsilon = ai_epsilon;
|
const auto zero_epsilon = ai_epsilon;
|
||||||
|
|
||||||
const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
|
const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
|
||||||
if (ok && preRotation.SquareLength() > zero_epsilon) {
|
if (ok && preRotation.SquareLength() > zero_epsilon) {
|
||||||
|
@ -3318,9 +3370,9 @@ FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std::
|
||||||
float vc = curve->GetValues().at(1);
|
float vc = curve->GetValues().at(1);
|
||||||
for (size_t n = 1; n < count; n++) {
|
for (size_t n = 1; n < count; n++) {
|
||||||
while (std::abs(vc - vp) >= 180.0f) {
|
while (std::abs(vc - vp) >= 180.0f) {
|
||||||
float step = std::floor(float(tc - tp) / (vc - vp) * 179.0f);
|
double step = std::floor(double(tc - tp) / std::abs(vc - vp) * 179.0f);
|
||||||
int64_t tnew = tp + int64_t(step);
|
int64_t tnew = tp + int64_t(step);
|
||||||
float vnew = vp + (vc - vp) * step / float(tc - tp);
|
float vnew = vp + (vc - vp) * float(step / (tc - tp));
|
||||||
if (tnew >= adj_start && tnew <= adj_stop) {
|
if (tnew >= adj_start && tnew <= adj_stop) {
|
||||||
Keys->push_back(tnew);
|
Keys->push_back(tnew);
|
||||||
Values->push_back(vnew);
|
Values->push_back(vnew);
|
||||||
|
@ -3625,6 +3677,12 @@ void FBXConverter::TransferDataToScene() {
|
||||||
|
|
||||||
std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures);
|
std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mSkeletons.empty()) {
|
||||||
|
mSceneOut->mSkeletons = new aiSkeleton *[mSkeletons.size()];
|
||||||
|
mSceneOut->mNumSkeletons = static_cast<unsigned int>(mSkeletons.size());
|
||||||
|
std::swap_ranges(mSkeletons.begin(), mSkeletons.end(), mSceneOut->mSkeletons);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FBXConverter::ConvertOrphanedEmbeddedTextures() {
|
void FBXConverter::ConvertOrphanedEmbeddedTextures() {
|
||||||
|
|
|
@ -75,7 +75,18 @@ typedef std::map<int64_t, morphKeyData*> morphAnimData;
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
|
||||||
|
class MeshGeometry;
|
||||||
|
|
||||||
|
using SkeletonBoneArray = std::vector<aiSkeletonBone *>;
|
||||||
|
using SkeletonBoneToMesh = std::map<aiMesh*, SkeletonBoneArray*>;
|
||||||
|
|
||||||
|
struct SkeletonBoneContainer {
|
||||||
|
std::vector<aiMesh *> MeshArray;
|
||||||
|
SkeletonBoneToMesh SkeletonBoneToMeshLookup;
|
||||||
|
};
|
||||||
|
|
||||||
class Document;
|
class Document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a FBX #Document to #aiScene
|
* Convert a FBX #Document to #aiScene
|
||||||
* @param out Empty scene to be populated
|
* @param out Empty scene to be populated
|
||||||
|
@ -180,12 +191,12 @@ private:
|
||||||
void SetupNodeMetadata(const Model& model, aiNode& nd);
|
void SetupNodeMetadata(const Model& model, aiNode& nd);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node);
|
void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
|
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
|
||||||
std::vector<unsigned int>
|
std::vector<unsigned int>
|
||||||
ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node);
|
ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::vector<unsigned int> ConvertLine(const LineGeometry& line, aiNode *root_node);
|
std::vector<unsigned int> ConvertLine(const LineGeometry& line, aiNode *root_node);
|
||||||
|
@ -194,15 +205,15 @@ private:
|
||||||
aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
|
aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
|
unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
|
||||||
aiNode *parent, aiNode *root_node);
|
aiNode *parent, aiNode *root_node);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::vector<unsigned int>
|
std::vector<unsigned int>
|
||||||
ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node);
|
ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, aiNode *parent, aiNode *root_node);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index,
|
unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, MatIndexArray::value_type index,
|
||||||
aiNode *parent, aiNode *root_node);
|
aiNode *parent, aiNode *root_node);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -216,14 +227,19 @@ private:
|
||||||
* - outputVertStartIndices is only used when a material index is specified, it gives for
|
* - outputVertStartIndices is only used when a material index is specified, it gives for
|
||||||
* each output vertex the DOM index it maps to.
|
* each output vertex the DOM index it maps to.
|
||||||
*/
|
*/
|
||||||
void ConvertWeights(aiMesh *out, const MeshGeometry &geo, aiNode *parent = nullptr,
|
void ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent = nullptr,
|
||||||
unsigned int materialIndex = NO_MATERIAL_SEPARATION,
|
unsigned int materialIndex = NO_MATERIAL_SEPARATION,
|
||||||
std::vector<unsigned int> *outputVertStartIndices = nullptr);
|
std::vector<unsigned int> *outputVertStartIndices = nullptr);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
|
||||||
|
aiNode *parent, unsigned int materialIndex, std::vector<unsigned int> *outputVertStartIndices,
|
||||||
|
SkeletonBoneContainer &skeletonContainer);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
||||||
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
|
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
|
||||||
std::vector<size_t> &count_out_indices, aiNode *parent );
|
std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform, aiNode *parent);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||||
|
@ -296,7 +312,8 @@ private:
|
||||||
void ConvertAnimationStack(const AnimationStack& st);
|
void ConvertAnimationStack(const AnimationStack& st);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node);
|
void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas,
|
||||||
|
const BlendShapeChannel* bsc, const AnimationCurveNode* node);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
|
void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
|
||||||
|
@ -445,6 +462,7 @@ private:
|
||||||
|
|
||||||
double anim_fps;
|
double anim_fps;
|
||||||
|
|
||||||
|
std::vector<aiSkeleton *> mSkeletons;
|
||||||
aiScene* const mSceneOut;
|
aiScene* const mSceneOut;
|
||||||
const FBX::Document& doc;
|
const FBX::Document& doc;
|
||||||
bool mRemoveEmptyBones;
|
bool mRemoveEmptyBones;
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2022, assimp team
|
Copyright (c) 2006-2022, assimp team
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -58,16 +57,14 @@ namespace FBX {
|
||||||
using namespace Util;
|
using namespace Util;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
|
||||||
: Object(id,element,name)
|
Object(id,element,name) {
|
||||||
{
|
|
||||||
const Scope& sc = GetRequiredScope(element);
|
const Scope& sc = GetRequiredScope(element);
|
||||||
|
|
||||||
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
|
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
|
||||||
props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
|
props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Deformer::~Deformer()
|
Deformer::~Deformer()
|
||||||
{
|
{
|
||||||
|
|
|
@ -544,7 +544,7 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
|
||||||
ai_assert( count != 0 );
|
ai_assert( count != 0 );
|
||||||
ai_assert( count <= MAX_CLASSNAMES);
|
ai_assert( count <= MAX_CLASSNAMES);
|
||||||
|
|
||||||
size_t lengths[MAX_CLASSNAMES];
|
size_t lengths[MAX_CLASSNAMES] = {};
|
||||||
|
|
||||||
const size_t c = count;
|
const size_t c = count;
|
||||||
for (size_t i = 0; i < c; ++i) {
|
for (size_t i = 0; i < c; ++i) {
|
||||||
|
|
|
@ -164,7 +164,7 @@ class NodeAttribute : public Object {
|
||||||
public:
|
public:
|
||||||
NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
||||||
|
|
||||||
virtual ~NodeAttribute();
|
virtual ~NodeAttribute() = default;
|
||||||
|
|
||||||
const PropertyTable& Props() const {
|
const PropertyTable& Props() const {
|
||||||
ai_assert(props.get());
|
ai_assert(props.get());
|
||||||
|
@ -180,7 +180,7 @@ class CameraSwitcher : public NodeAttribute {
|
||||||
public:
|
public:
|
||||||
CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
||||||
|
|
||||||
virtual ~CameraSwitcher();
|
virtual ~CameraSwitcher() = default;
|
||||||
|
|
||||||
int CameraID() const {
|
int CameraID() const {
|
||||||
return cameraId;
|
return cameraId;
|
||||||
|
@ -225,7 +225,7 @@ class Camera : public NodeAttribute {
|
||||||
public:
|
public:
|
||||||
Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
||||||
|
|
||||||
virtual ~Camera();
|
virtual ~Camera() = default;
|
||||||
|
|
||||||
fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0))
|
fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0))
|
||||||
fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0))
|
fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0))
|
||||||
|
@ -250,21 +250,21 @@ public:
|
||||||
class Null : public NodeAttribute {
|
class Null : public NodeAttribute {
|
||||||
public:
|
public:
|
||||||
Null(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
Null(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
||||||
virtual ~Null();
|
virtual ~Null() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** DOM base class for FBX limb node markers attached to a node */
|
/** DOM base class for FBX limb node markers attached to a node */
|
||||||
class LimbNode : public NodeAttribute {
|
class LimbNode : public NodeAttribute {
|
||||||
public:
|
public:
|
||||||
LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
||||||
virtual ~LimbNode();
|
virtual ~LimbNode() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** DOM base class for FBX lights attached to a node */
|
/** DOM base class for FBX lights attached to a node */
|
||||||
class Light : public NodeAttribute {
|
class Light : public NodeAttribute {
|
||||||
public:
|
public:
|
||||||
Light(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
Light(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
||||||
virtual ~Light();
|
virtual ~Light() = default;
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
Type_Point,
|
Type_Point,
|
||||||
|
@ -690,7 +690,7 @@ using KeyValueList = std::vector<float>;
|
||||||
class AnimationCurve : public Object {
|
class AnimationCurve : public Object {
|
||||||
public:
|
public:
|
||||||
AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc);
|
AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc);
|
||||||
virtual ~AnimationCurve();
|
virtual ~AnimationCurve() = default;
|
||||||
|
|
||||||
/** get list of keyframe positions (time).
|
/** get list of keyframe positions (time).
|
||||||
* Invariant: |GetKeys()| > 0 */
|
* Invariant: |GetKeys()| > 0 */
|
||||||
|
@ -731,7 +731,7 @@ public:
|
||||||
AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc,
|
AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc,
|
||||||
const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0);
|
const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0);
|
||||||
|
|
||||||
virtual ~AnimationCurveNode();
|
virtual ~AnimationCurveNode() = default;
|
||||||
|
|
||||||
const PropertyTable& Props() const {
|
const PropertyTable& Props() const {
|
||||||
ai_assert(props.get());
|
ai_assert(props.get());
|
||||||
|
@ -776,7 +776,7 @@ using AnimationCurveNodeList = std::vector<const AnimationCurveNode*>;
|
||||||
class AnimationLayer : public Object {
|
class AnimationLayer : public Object {
|
||||||
public:
|
public:
|
||||||
AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc);
|
AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc);
|
||||||
virtual ~AnimationLayer();
|
virtual ~AnimationLayer() = default;
|
||||||
|
|
||||||
const PropertyTable& Props() const {
|
const PropertyTable& Props() const {
|
||||||
ai_assert(props.get());
|
ai_assert(props.get());
|
||||||
|
@ -799,7 +799,7 @@ using AnimationLayerList = std::vector<const AnimationLayer*>;
|
||||||
class AnimationStack : public Object {
|
class AnimationStack : public Object {
|
||||||
public:
|
public:
|
||||||
AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc);
|
AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc);
|
||||||
virtual ~AnimationStack();
|
virtual ~AnimationStack() = default;
|
||||||
|
|
||||||
fbx_simple_property(LocalStart, int64_t, 0L)
|
fbx_simple_property(LocalStart, int64_t, 0L)
|
||||||
fbx_simple_property(LocalStop, int64_t, 0L)
|
fbx_simple_property(LocalStop, int64_t, 0L)
|
||||||
|
|
|
@ -59,14 +59,12 @@ namespace Util {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
|
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
|
||||||
void DOMError(const std::string& message, const Token& token)
|
void DOMError(const std::string& message, const Token& token) {
|
||||||
{
|
|
||||||
throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message);
|
throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void DOMError(const std::string& message, const Element* element /*= nullptr*/)
|
void DOMError(const std::string& message, const Element* element /*= nullptr*/) {
|
||||||
{
|
|
||||||
if(element) {
|
if(element) {
|
||||||
DOMError(message,element->KeyToken());
|
DOMError(message,element->KeyToken());
|
||||||
}
|
}
|
||||||
|
@ -76,8 +74,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// print warning, do return
|
// print warning, do return
|
||||||
void DOMWarning(const std::string& message, const Token& token)
|
void DOMWarning(const std::string& message, const Token& token) {
|
||||||
{
|
|
||||||
if(DefaultLogger::get()) {
|
if(DefaultLogger::get()) {
|
||||||
ASSIMP_LOG_WARN("FBX-DOM", Util::GetTokenText(&token), message);
|
ASSIMP_LOG_WARN("FBX-DOM", Util::GetTokenText(&token), message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,13 +74,11 @@ std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline
|
inline const T* ProcessSimpleConnection(const Connection& con,
|
||||||
const T* ProcessSimpleConnection(const Connection& con,
|
bool is_object_property_conn,
|
||||||
bool is_object_property_conn,
|
const char* name,
|
||||||
const char* name,
|
const Element& element,
|
||||||
const Element& element,
|
const char** propNameOut = nullptr) {
|
||||||
const char** propNameOut = nullptr)
|
|
||||||
{
|
|
||||||
if (is_object_property_conn && !con.PropertyName().length()) {
|
if (is_object_property_conn && !con.PropertyName().length()) {
|
||||||
DOMWarning("expected incoming " + std::string(name) +
|
DOMWarning("expected incoming " + std::string(name) +
|
||||||
" link to be an object-object connection, ignoring",
|
" link to be an object-object connection, ignoring",
|
||||||
|
|
|
@ -255,7 +255,7 @@ void FBXExporter::WriteBinaryHeader()
|
||||||
|
|
||||||
void FBXExporter::WriteBinaryFooter()
|
void FBXExporter::WriteBinaryFooter()
|
||||||
{
|
{
|
||||||
outfile->Write(NULL_RECORD.c_str(), NULL_RECORD.size(), 1);
|
outfile->Write(NULL_RECORD, NumNullRecords, 1);
|
||||||
|
|
||||||
outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1);
|
outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1);
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ struct ImportSettings {
|
||||||
readLights(true),
|
readLights(true),
|
||||||
readAnimations(true),
|
readAnimations(true),
|
||||||
readWeights(true),
|
readWeights(true),
|
||||||
|
useSkeleton(false),
|
||||||
preservePivots(true),
|
preservePivots(true),
|
||||||
optimizeEmptyAnimationCurves(true),
|
optimizeEmptyAnimationCurves(true),
|
||||||
useLegacyEmbeddedTextureNaming(false),
|
useLegacyEmbeddedTextureNaming(false),
|
||||||
|
@ -112,6 +113,11 @@ struct ImportSettings {
|
||||||
* Default value is true. */
|
* Default value is true. */
|
||||||
bool readWeights;
|
bool readWeights;
|
||||||
|
|
||||||
|
/** will convert all animation data into a skeleton (experimental)
|
||||||
|
* Default value is false.
|
||||||
|
*/
|
||||||
|
bool useSkeleton;
|
||||||
|
|
||||||
/** preserve transformation pivots and offsets. Since these can
|
/** preserve transformation pivots and offsets. Since these can
|
||||||
* not directly be represented in assimp, additional dummy
|
* not directly be represented in assimp, additional dummy
|
||||||
* nodes will be generated. Note that settings this to false
|
* nodes will be generated. Note that settings this to false
|
||||||
|
|
|
@ -90,12 +90,9 @@ static const aiImporterDesc desc = {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by #Importer
|
// Constructor to be privately used by #Importer
|
||||||
FBXImporter::FBXImporter() {
|
FBXImporter::FBXImporter() :
|
||||||
}
|
mSettings() {
|
||||||
|
// empty
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Destructor, private as well
|
|
||||||
FBXImporter::~FBXImporter() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -115,20 +112,21 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Setup configuration properties for the loader
|
// Setup configuration properties for the loader
|
||||||
void FBXImporter::SetupProperties(const Importer *pImp) {
|
void FBXImporter::SetupProperties(const Importer *pImp) {
|
||||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||||
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||||
settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
|
mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
|
||||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||||
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||||
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
||||||
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||||
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
||||||
|
mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -155,7 +153,7 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
contents[contents.size() - 1] = 0;
|
contents[contents.size() - 1] = 0;
|
||||||
const char *const begin = &*contents.begin();
|
const char *const begin = &*contents.begin();
|
||||||
|
|
||||||
// broadphase tokenizing pass in which we identify the core
|
// broad-phase tokenized pass in which we identify the core
|
||||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||||
TokenList tokens;
|
TokenList tokens;
|
||||||
try {
|
try {
|
||||||
|
@ -173,15 +171,14 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
||||||
Parser parser(tokens, is_binary);
|
Parser parser(tokens, is_binary);
|
||||||
|
|
||||||
// take the raw parse-tree and convert it to a FBX DOM
|
// take the raw parse-tree and convert it to a FBX DOM
|
||||||
Document doc(parser, settings);
|
Document doc(parser, mSettings);
|
||||||
|
|
||||||
// convert the FBX DOM to aiScene
|
// convert the FBX DOM to aiScene
|
||||||
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
|
||||||
|
|
||||||
// size relative to cm
|
// size relative to cm
|
||||||
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
||||||
if (size_relative_to_cm == 0.0)
|
if (size_relative_to_cm == 0.0) {
|
||||||
{
|
|
||||||
// BaseImporter later asserts that fileScale is non-zero.
|
// BaseImporter later asserts that fileScale is non-zero.
|
||||||
ThrowException("The UnitScaleFactor must be non-zero");
|
ThrowException("The UnitScaleFactor must be non-zero");
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,13 +69,14 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
|
||||||
// -------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------
|
||||||
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
|
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
|
||||||
public:
|
public:
|
||||||
|
/// @brief The class constructor.
|
||||||
FBXImporter();
|
FBXImporter();
|
||||||
~FBXImporter() override;
|
|
||||||
|
|
||||||
// --------------------
|
/// @brief The class destructor, default implementation.
|
||||||
bool CanRead(const std::string &pFile,
|
~FBXImporter() override = default;
|
||||||
IOSystem *pIOHandler,
|
|
||||||
bool checkSig) const override;
|
/// @brief Will check the file for readability.
|
||||||
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// --------------------
|
// --------------------
|
||||||
|
@ -90,7 +91,7 @@ protected:
|
||||||
IOSystem *pIOHandler) override;
|
IOSystem *pIOHandler) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FBX::ImportSettings settings;
|
FBX::ImportSettings mSettings;
|
||||||
}; // !class FBXImporter
|
}; // !class FBXImporter
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2022, assimp team
|
Copyright (c) 2006-2022, assimp team
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -54,18 +53,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "FBXImportSettings.h"
|
#include "FBXImportSettings.h"
|
||||||
#include "FBXDocumentUtil.h"
|
#include "FBXDocumentUtil.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
|
||||||
using namespace Util;
|
using namespace Util;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) :
|
||||||
: Object(id, element, name)
|
Object(id, element, name), skin() {
|
||||||
, skin()
|
const std::vector<const Connection*> &conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
|
||||||
{
|
|
||||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
|
|
||||||
for(const Connection* con : conns) {
|
for(const Connection* con : conns) {
|
||||||
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||||
if(sk) {
|
if(sk) {
|
||||||
|
@ -78,12 +74,6 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
Geometry::~Geometry()
|
|
||||||
{
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
|
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
|
||||||
return blendShapes;
|
return blendShapes;
|
||||||
|
@ -183,18 +173,12 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
||||||
if(doc.Settings().readAllLayers || index == 0) {
|
if(doc.Settings().readAllLayers || index == 0) {
|
||||||
const Scope& layer = GetRequiredScope(*(*it).second);
|
const Scope& layer = GetRequiredScope(*(*it).second);
|
||||||
ReadLayer(layer);
|
ReadLayer(layer);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
FBXImporter::LogWarn("ignoring additional geometry layers");
|
FBXImporter::LogWarn("ignoring additional geometry layers");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
MeshGeometry::~MeshGeometry() {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
|
const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
|
||||||
return m_vertices;
|
return m_vertices;
|
||||||
|
|
|
@ -55,22 +55,25 @@ namespace FBX {
|
||||||
/**
|
/**
|
||||||
* DOM base class for all kinds of FBX geometry
|
* DOM base class for all kinds of FBX geometry
|
||||||
*/
|
*/
|
||||||
class Geometry : public Object
|
class Geometry : public Object {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
/// @brief The class constructor with all parameters.
|
||||||
|
/// @param id The id.
|
||||||
|
/// @param element
|
||||||
|
/// @param name
|
||||||
|
/// @param doc
|
||||||
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
|
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
|
||||||
virtual ~Geometry();
|
virtual ~Geometry() = default;
|
||||||
|
|
||||||
/** Get the Skin attached to this geometry or nullptr */
|
/// Get the Skin attached to this geometry or nullptr
|
||||||
const Skin* DeformerSkin() const;
|
const Skin* DeformerSkin() const;
|
||||||
|
|
||||||
/** Get the BlendShape attached to this geometry or nullptr */
|
/// Get the BlendShape attached to this geometry or nullptr
|
||||||
const std::vector<const BlendShape*>& GetBlendShapes() const;
|
const std::vector<const BlendShape*>& GetBlendShapes() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Skin* skin;
|
const Skin* skin;
|
||||||
std::vector<const BlendShape*> blendShapes;
|
std::vector<const BlendShape*> blendShapes;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<int> MatIndexArray;
|
typedef std::vector<int> MatIndexArray;
|
||||||
|
@ -79,14 +82,13 @@ typedef std::vector<int> MatIndexArray;
|
||||||
/**
|
/**
|
||||||
* DOM class for FBX geometry of type "Mesh"
|
* DOM class for FBX geometry of type "Mesh"
|
||||||
*/
|
*/
|
||||||
class MeshGeometry : public Geometry
|
class MeshGeometry : public Geometry {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
/** The class constructor */
|
/** The class constructor */
|
||||||
MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
|
MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
|
||||||
|
|
||||||
/** The class destructor */
|
/** The class destructor */
|
||||||
virtual ~MeshGeometry();
|
virtual ~MeshGeometry() = default;
|
||||||
|
|
||||||
/** Get a list of all vertex points, non-unique*/
|
/** Get a list of all vertex points, non-unique*/
|
||||||
const std::vector<aiVector3D>& GetVertices() const;
|
const std::vector<aiVector3D>& GetVertices() const;
|
||||||
|
@ -130,6 +132,7 @@ public:
|
||||||
/** Determine the face to which a particular output vertex index belongs.
|
/** Determine the face to which a particular output vertex index belongs.
|
||||||
* This mapping is always unique. */
|
* This mapping is always unique. */
|
||||||
unsigned int FaceForVertexIndex( unsigned int in_index ) const;
|
unsigned int FaceForVertexIndex( unsigned int in_index ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ReadLayer( const Scope& layer );
|
void ReadLayer( const Scope& layer );
|
||||||
void ReadLayerElement( const Scope& layerElement );
|
void ReadLayerElement( const Scope& layerElement );
|
||||||
|
|
|
@ -57,114 +57,65 @@ namespace FBX {
|
||||||
using namespace Util;
|
using namespace Util;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
NodeAttribute::NodeAttribute(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
|
||||||
: Object(id,element,name)
|
Object(id, element, name), props() {
|
||||||
, props()
|
const Scope &sc = GetRequiredScope(element);
|
||||||
{
|
|
||||||
const Scope& sc = GetRequiredScope(element);
|
|
||||||
|
|
||||||
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
|
const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||||
|
|
||||||
// hack on the deriving type but Null/LimbNode attributes are the only case in which
|
// hack on the deriving type but Null/LimbNode attributes are the only case in which
|
||||||
// the property table is by design absent and no warning should be generated
|
// the property table is by design absent and no warning should be generated
|
||||||
// for it.
|
// for it.
|
||||||
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
|
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
|
||||||
props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb);
|
props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
NodeAttribute::~NodeAttribute()
|
CameraSwitcher::CameraSwitcher(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
|
||||||
{
|
NodeAttribute(id, element, doc, name) {
|
||||||
// empty
|
const Scope &sc = GetRequiredScope(element);
|
||||||
}
|
const Element *const CameraId = sc["CameraId"];
|
||||||
|
const Element *const CameraName = sc["CameraName"];
|
||||||
|
const Element *const CameraIndexName = sc["CameraIndexName"];
|
||||||
|
|
||||||
|
if (CameraId) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId, 0));
|
||||||
CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
|
||||||
: NodeAttribute(id,element,doc,name)
|
|
||||||
{
|
|
||||||
const Scope& sc = GetRequiredScope(element);
|
|
||||||
const Element* const CameraId = sc["CameraId"];
|
|
||||||
const Element* const CameraName = sc["CameraName"];
|
|
||||||
const Element* const CameraIndexName = sc["CameraIndexName"];
|
|
||||||
|
|
||||||
if(CameraId) {
|
|
||||||
cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CameraName) {
|
if (CameraName) {
|
||||||
cameraName = GetRequiredToken(*CameraName,0).StringContents();
|
cameraName = GetRequiredToken(*CameraName, 0).StringContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CameraIndexName && CameraIndexName->Tokens().size()) {
|
if (CameraIndexName && CameraIndexName->Tokens().size()) {
|
||||||
cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
|
cameraIndexName = GetRequiredToken(*CameraIndexName, 0).StringContents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
CameraSwitcher::~CameraSwitcher()
|
Camera::Camera(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
|
||||||
{
|
NodeAttribute(id, element, doc, name) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
Light::Light(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
|
||||||
: NodeAttribute(id,element,doc,name)
|
NodeAttribute(id, element, doc, name) {
|
||||||
{
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Camera::~Camera()
|
Null::Null(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
|
||||||
{
|
NodeAttribute(id, element, doc, name) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
LimbNode::LimbNode(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
|
||||||
: NodeAttribute(id,element,doc,name)
|
NodeAttribute(id, element, doc, name) {
|
||||||
{
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace FBX
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
#endif // ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||||
Light::~Light()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
Null::Null(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
|
||||||
: NodeAttribute(id,element,doc,name)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
Null::~Null()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
LimbNode::LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
|
||||||
: NodeAttribute(id,element,doc,name)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
LimbNode::~LimbNode()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -162,12 +162,6 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
|
||||||
while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
|
while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
Element::~Element()
|
|
||||||
{
|
|
||||||
// no need to delete tokens, they are owned by the parser
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Scope::Scope(Parser& parser,bool topLevel)
|
Scope::Scope(Parser& parser,bool topLevel)
|
||||||
{
|
{
|
||||||
|
@ -226,12 +220,6 @@ Parser::Parser (const TokenList& tokens, bool is_binary)
|
||||||
root.reset(new Scope(*this,true));
|
root.reset(new Scope(*this,true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
Parser::~Parser()
|
|
||||||
{
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TokenPtr Parser::AdvanceToNextToken()
|
TokenPtr Parser::AdvanceToNextToken()
|
||||||
{
|
{
|
||||||
|
@ -961,8 +949,7 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of uints
|
// read an array of uints
|
||||||
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) {
|
||||||
{
|
|
||||||
out.resize( 0 );
|
out.resize( 0 );
|
||||||
const TokenList& tok = el.Tokens();
|
const TokenList& tok = el.Tokens();
|
||||||
if(tok.empty()) {
|
if(tok.empty()) {
|
||||||
|
@ -1186,7 +1173,6 @@ aiMatrix4x4 ReadMatrix(const Element& element)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// wrapper around ParseTokenAsString() with ParseError handling
|
// wrapper around ParseTokenAsString() with ParseError handling
|
||||||
std::string ParseTokenAsString(const Token& t)
|
std::string ParseTokenAsString(const Token& t)
|
||||||
|
|
|
@ -87,7 +87,7 @@ class Element
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Element(const Token& key_token, Parser& parser);
|
Element(const Token& key_token, Parser& parser);
|
||||||
~Element();
|
~Element() = default;
|
||||||
|
|
||||||
const Scope* Compound() const {
|
const Scope* Compound() const {
|
||||||
return compound.get();
|
return compound.get();
|
||||||
|
@ -160,7 +160,7 @@ public:
|
||||||
/** Parse given a token list. Does not take ownership of the tokens -
|
/** Parse given a token list. Does not take ownership of the tokens -
|
||||||
* the objects must persist during the entire parser lifetime */
|
* the objects must persist during the entire parser lifetime */
|
||||||
Parser (const TokenList& tokens,bool is_binary);
|
Parser (const TokenList& tokens,bool is_binary);
|
||||||
~Parser();
|
~Parser() = default;
|
||||||
|
|
||||||
const Scope& GetRootScope() const {
|
const Scope& GetRootScope() const {
|
||||||
return *root.get();
|
return *root.get();
|
||||||
|
|
|
@ -57,9 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
// Assimp specific M3D configuration. Comment out these defines to remove functionality
|
// Assimp specific M3D configuration. Comment out these defines to remove functionality
|
||||||
//#define ASSIMP_USE_M3D_READFILECB
|
//#define ASSIMP_USE_M3D_READFILECB
|
||||||
|
|
||||||
// Share stb_image's PNG loader with other importers/exporters instead of bringing our own copy.
|
#include "Common/StbCommon.h"
|
||||||
#define STBI_ONLY_PNG
|
|
||||||
#include <stb/stb_image.h>
|
|
||||||
|
|
||||||
#include "m3d.h"
|
#include "m3d.h"
|
||||||
|
|
||||||
|
|
|
@ -908,7 +908,7 @@ Ref<Node> FindSkeletonRootJoint(Ref<Skin> &skinRef) {
|
||||||
do {
|
do {
|
||||||
startNodeRef = parentNodeRef;
|
startNodeRef = parentNodeRef;
|
||||||
parentNodeRef = startNodeRef->parent;
|
parentNodeRef = startNodeRef->parent;
|
||||||
} while (!parentNodeRef->jointName.empty());
|
} while (parentNodeRef && !parentNodeRef->jointName.empty());
|
||||||
|
|
||||||
return parentNodeRef;
|
return parentNodeRef;
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,6 +167,7 @@ SET( Logging_SRCS
|
||||||
SOURCE_GROUP(Logging FILES ${Logging_SRCS})
|
SOURCE_GROUP(Logging FILES ${Logging_SRCS})
|
||||||
|
|
||||||
SET( Common_SRCS
|
SET( Common_SRCS
|
||||||
|
Common/StbCommon.h
|
||||||
Common/Compression.cpp
|
Common/Compression.cpp
|
||||||
Common/Compression.h
|
Common/Compression.h
|
||||||
Common/BaseImporter.cpp
|
Common/BaseImporter.cpp
|
||||||
|
@ -1099,8 +1100,6 @@ if(MSVC10)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
ADD_DEFINITIONS( -DASSIMP_BUILD_DLL_EXPORT )
|
|
||||||
|
|
||||||
IF( MSVC OR "${CMAKE_CXX_SIMULATE_ID}" MATCHES "MSVC") # clang with MSVC ABI
|
IF( MSVC OR "${CMAKE_CXX_SIMULATE_ID}" MATCHES "MSVC") # clang with MSVC ABI
|
||||||
ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
|
ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
|
||||||
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
|
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
|
||||||
|
@ -1177,6 +1176,13 @@ ENDIF()
|
||||||
ADD_LIBRARY( assimp ${assimp_src} )
|
ADD_LIBRARY( assimp ${assimp_src} )
|
||||||
ADD_LIBRARY(assimp::assimp ALIAS assimp)
|
ADD_LIBRARY(assimp::assimp ALIAS assimp)
|
||||||
|
|
||||||
|
# Add or remove dllexport tags depending on the library type.
|
||||||
|
IF (BUILD_SHARED_LIBS)
|
||||||
|
TARGET_COMPILE_DEFINITIONS(assimp PRIVATE ASSIMP_BUILD_DLL_EXPORT)
|
||||||
|
ELSE ()
|
||||||
|
TARGET_COMPILE_DEFINITIONS(assimp PRIVATE OPENDDL_STATIC_LIBARY)
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
|
TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
|
||||||
|
|
||||||
IF (ASSIMP_WARNINGS_AS_ERRORS)
|
IF (ASSIMP_WARNINGS_AS_ERRORS)
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2022, assimp team
|
Copyright (c) 2006-2022, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -1282,18 +1280,13 @@ ASSIMP_API void aiQuaternionInterpolate(
|
||||||
# define STBI_ONLY_PNG
|
# define STBI_ONLY_PNG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Ensure all symbols are linked correctly
|
||||||
#if ASSIMP_NEEDS_STB_IMAGE
|
#if ASSIMP_NEEDS_STB_IMAGE
|
||||||
|
// Share stb_image's PNG loader with other importers/exporters instead of bringing our own copy.
|
||||||
# if _MSC_VER // "unreferenced function has been removed" (SSE2 detection routine in x64 builds)
|
# define STBI_ONLY_PNG
|
||||||
# pragma warning(push)
|
# ifdef ASSIMP_USE_STB_IMAGE_STATIC
|
||||||
# pragma warning(disable: 4505)
|
# define STB_IMAGE_STATIC
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# define STB_IMAGE_IMPLEMENTATION
|
# define STB_IMAGE_IMPLEMENTATION
|
||||||
# include "stb/stb_image.h"
|
# include "Common/StbCommon.h"
|
||||||
|
|
||||||
# if _MSC_VER
|
|
||||||
# pragma warning(pop)
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -300,10 +300,10 @@ private:
|
||||||
|
|
||||||
const char separator = getOsSeparator();
|
const char separator = getOsSeparator();
|
||||||
for (it = in.begin(); it != in.end(); ++it) {
|
for (it = in.begin(); it != in.end(); ++it) {
|
||||||
int remaining = std::distance(in.end(), it);
|
const size_t remaining = std::distance(in.end(), it);
|
||||||
// Exclude :// and \\, which remain untouched.
|
// Exclude :// and \\, which remain untouched.
|
||||||
// https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
|
// https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
|
||||||
if (remaining >= 3 && !strncmp(&*it, "://", 3 )) {
|
if (remaining >= 3u && !strncmp(&*it, "://", 3 )) {
|
||||||
it += 3;
|
it += 3;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2022, assimp team
|
Copyright (c) 2006-2022, assimp team
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -97,13 +96,14 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
|
||||||
const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation;
|
const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation;
|
||||||
aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
|
aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
|
||||||
ai_real distanceToChild = childpos.Length();
|
ai_real distanceToChild = childpos.Length();
|
||||||
if (distanceToChild < 0.0001)
|
if (distanceToChild < ai_epsilon) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
aiVector3D up = aiVector3D(childpos).Normalize();
|
aiVector3D up = aiVector3D(childpos).Normalize();
|
||||||
|
|
||||||
aiVector3D orth(1.0, 0.0, 0.0);
|
aiVector3D orth(1.0, 0.0, 0.0);
|
||||||
if (std::fabs(orth * up) > 0.99)
|
if (std::fabs(orth * up) > 0.99) {
|
||||||
orth.Set(0.0, 1.0, 0.0);
|
orth.Set(0.0, 1.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
aiVector3D front = (up ^ orth).Normalize();
|
aiVector3D front = (up ^ orth).Normalize();
|
||||||
aiVector3D side = (front ^ up).Normalize();
|
aiVector3D side = (front ^ up).Normalize();
|
||||||
|
@ -183,8 +183,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
|
||||||
// add all the vertices to the bone's influences
|
// add all the vertices to the bone's influences
|
||||||
bone->mNumWeights = numVertices;
|
bone->mNumWeights = numVertices;
|
||||||
bone->mWeights = new aiVertexWeight[numVertices];
|
bone->mWeights = new aiVertexWeight[numVertices];
|
||||||
for (unsigned int a = 0; a < numVertices; a++)
|
for (unsigned int a = 0; a < numVertices; ++a) {
|
||||||
bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0);
|
bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
// HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
|
// HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
|
||||||
// them to the array, but I'm tired now and I'm annoyed.
|
// them to the array, but I'm tired now and I'm annoyed.
|
||||||
|
@ -194,8 +195,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// and finally recurse into the children list
|
// and finally recurse into the children list
|
||||||
for (unsigned int a = 0; a < pNode->mNumChildren; a++)
|
for (unsigned int a = 0; a < pNode->mNumChildren; ++a) {
|
||||||
CreateGeometry(pNode->mChildren[a]);
|
CreateGeometry(pNode->mChildren[a]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2022, assimp team
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if _MSC_VER // "unreferenced function has been removed" (SSE2 detection routine in x64 builds)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4505)
|
||||||
|
#else
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "stb/stb_image.h"
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#else
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
|
@ -135,6 +135,9 @@ ASSIMP_API aiScene::aiScene() :
|
||||||
mNumCameras(0),
|
mNumCameras(0),
|
||||||
mCameras(nullptr),
|
mCameras(nullptr),
|
||||||
mMetaData(nullptr),
|
mMetaData(nullptr),
|
||||||
|
mName(),
|
||||||
|
mNumSkeletons(0),
|
||||||
|
mSkeletons(nullptr),
|
||||||
mPrivate(new Assimp::ScenePrivateData()) {
|
mPrivate(new Assimp::ScenePrivateData()) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
@ -180,7 +183,8 @@ ASSIMP_API aiScene::~aiScene() {
|
||||||
delete[] mCameras;
|
delete[] mCameras;
|
||||||
|
|
||||||
aiMetadata::Dealloc(mMetaData);
|
aiMetadata::Dealloc(mMetaData);
|
||||||
mMetaData = nullptr;
|
|
||||||
|
delete[] mSkeletons;
|
||||||
|
|
||||||
delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
|
delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ Other:
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "stb/stb_image.h"
|
#include "Common/StbCommon.h"
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
########################################################################
|
########################################################################
|
||||||
|
# Note: CMake support is community-based. The maintainers do not use CMake
|
||||||
|
# internally.
|
||||||
|
#
|
||||||
# CMake build script for Google Test.
|
# CMake build script for Google Test.
|
||||||
#
|
#
|
||||||
# To run the tests for Google Test itself on Linux, use 'make test' or
|
# To run the tests for Google Test itself on Linux, use 'make test' or
|
||||||
# ctest. You can select which tests to run using 'ctest -R regex'.
|
# ctest. You can select which tests to run using 'ctest -R regex'.
|
||||||
# For more options, run 'ctest --help'.
|
# For more options, run 'ctest --help'.
|
||||||
|
|
||||||
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
|
|
||||||
# make it prominent in the GUI.
|
|
||||||
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
|
|
||||||
|
|
||||||
# When other libraries are using a shared version of runtime libraries,
|
# When other libraries are using a shared version of runtime libraries,
|
||||||
# Google Test also has to use one.
|
# Google Test also has to use one.
|
||||||
option(
|
option(
|
||||||
|
@ -44,13 +43,45 @@ endif()
|
||||||
# as ${gtest_SOURCE_DIR} and to the root binary directory as
|
# as ${gtest_SOURCE_DIR} and to the root binary directory as
|
||||||
# ${gtest_BINARY_DIR}.
|
# ${gtest_BINARY_DIR}.
|
||||||
# Language "C" is required for find_package(Threads).
|
# Language "C" is required for find_package(Threads).
|
||||||
project(gtest CXX C)
|
|
||||||
cmake_minimum_required(VERSION 3.10)
|
# Project version:
|
||||||
|
|
||||||
|
if (CMAKE_VERSION VERSION_LESS 3.0)
|
||||||
|
project(gtest CXX C)
|
||||||
|
set(PROJECT_VERSION ${GOOGLETEST_VERSION})
|
||||||
|
else()
|
||||||
|
cmake_policy(SET CMP0048 NEW)
|
||||||
|
project(gtest VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
|
||||||
|
endif()
|
||||||
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
|
||||||
|
if (POLICY CMP0063) # Visibility
|
||||||
|
cmake_policy(SET CMP0063 NEW)
|
||||||
|
endif (POLICY CMP0063)
|
||||||
|
|
||||||
if (COMMAND set_up_hermetic_build)
|
if (COMMAND set_up_hermetic_build)
|
||||||
set_up_hermetic_build()
|
set_up_hermetic_build()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# These commands only run if this is the main project
|
||||||
|
if(CMAKE_PROJECT_NAME STREQUAL "gtest" OR CMAKE_PROJECT_NAME STREQUAL "googletest-distribution")
|
||||||
|
|
||||||
|
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
|
||||||
|
# make it prominent in the GUI.
|
||||||
|
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
|
||||||
|
|
||||||
|
else()
|
||||||
|
|
||||||
|
mark_as_advanced(
|
||||||
|
gtest_force_shared_crt
|
||||||
|
gtest_build_tests
|
||||||
|
gtest_build_samples
|
||||||
|
gtest_disable_pthreads
|
||||||
|
gtest_hide_internal_symbols)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
if (gtest_hide_internal_symbols)
|
if (gtest_hide_internal_symbols)
|
||||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||||
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
|
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
|
||||||
|
@ -61,24 +92,34 @@ include(cmake/internal_utils.cmake)
|
||||||
|
|
||||||
config_compiler_and_linker() # Defined in internal_utils.cmake.
|
config_compiler_and_linker() # Defined in internal_utils.cmake.
|
||||||
|
|
||||||
# Where Google Test's .h files can be found.
|
# Needed to set the namespace for both the export targets and the
|
||||||
include_directories(
|
# alias libraries
|
||||||
${gtest_SOURCE_DIR}/include
|
set(cmake_package_name GTest CACHE INTERNAL "")
|
||||||
${gtest_SOURCE_DIR})
|
|
||||||
|
|
||||||
# Where Google Test's libraries can be found.
|
# Create the CMake package file descriptors.
|
||||||
link_directories(${gtest_BINARY_DIR}/src)
|
if (INSTALL_GTEST)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
# Summary of tuple support for Microsoft Visual Studio:
|
set(targets_export_name ${cmake_package_name}Targets CACHE INTERNAL "")
|
||||||
# Compiler version(MS) version(cmake) Support
|
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated" CACHE INTERNAL "")
|
||||||
# ---------- ----------- -------------- -----------------------------
|
set(cmake_files_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${cmake_package_name}")
|
||||||
# <= VS 2010 <= 10 <= 1600 Use Google Tests's own tuple.
|
set(version_file "${generated_dir}/${cmake_package_name}ConfigVersion.cmake")
|
||||||
# VS 2012 11 1700 std::tr1::tuple + _VARIADIC_MAX=10
|
write_basic_package_version_file(${version_file} VERSION ${GOOGLETEST_VERSION} COMPATIBILITY AnyNewerVersion)
|
||||||
# VS 2013 12 1800 std::tr1::tuple
|
install(EXPORT ${targets_export_name}
|
||||||
if (MSVC AND MSVC_VERSION EQUAL 1700)
|
NAMESPACE ${cmake_package_name}::
|
||||||
add_definitions(/D _VARIADIC_MAX=10)
|
DESTINATION ${cmake_files_install_dir})
|
||||||
|
set(config_file "${generated_dir}/${cmake_package_name}Config.cmake")
|
||||||
|
configure_package_config_file("${gtest_SOURCE_DIR}/cmake/Config.cmake.in"
|
||||||
|
"${config_file}" INSTALL_DESTINATION ${cmake_files_install_dir})
|
||||||
|
install(FILES ${version_file} ${config_file}
|
||||||
|
DESTINATION ${cmake_files_install_dir})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Where Google Test's .h files can be found.
|
||||||
|
set(gtest_build_include_dirs
|
||||||
|
"${gtest_SOURCE_DIR}/include"
|
||||||
|
"${gtest_SOURCE_DIR}")
|
||||||
|
include_directories(${gtest_build_include_dirs})
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
#
|
#
|
||||||
# Defines the gtest & gtest_main libraries. User tests should link
|
# Defines the gtest & gtest_main libraries. User tests should link
|
||||||
|
@ -88,24 +129,26 @@ endif()
|
||||||
# are used for other targets, to ensure that gtest can be compiled by a user
|
# are used for other targets, to ensure that gtest can be compiled by a user
|
||||||
# aggressive about warnings.
|
# aggressive about warnings.
|
||||||
cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)
|
cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)
|
||||||
|
set_target_properties(gtest PROPERTIES VERSION ${GOOGLETEST_VERSION})
|
||||||
cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
|
cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
|
||||||
target_link_libraries(gtest_main gtest)
|
set_target_properties(gtest_main PROPERTIES VERSION ${GOOGLETEST_VERSION})
|
||||||
|
|
||||||
# If the CMake version supports it, attach header directory information
|
# If the CMake version supports it, attach header directory information
|
||||||
# to the targets for when we are part of a parent build (ie being pulled
|
# to the targets for when we are part of a parent build (ie being pulled
|
||||||
# in via add_subdirectory() rather than being a standalone build).
|
# in via add_subdirectory() rather than being a standalone build).
|
||||||
if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
|
if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
|
||||||
target_include_directories(gtest INTERFACE "${gtest_SOURCE_DIR}/include")
|
target_include_directories(gtest SYSTEM INTERFACE
|
||||||
target_include_directories(gtest_main INTERFACE "${gtest_SOURCE_DIR}/include")
|
"$<BUILD_INTERFACE:${gtest_build_include_dirs}>"
|
||||||
|
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||||
|
target_include_directories(gtest_main SYSTEM INTERFACE
|
||||||
|
"$<BUILD_INTERFACE:${gtest_build_include_dirs}>"
|
||||||
|
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||||
endif()
|
endif()
|
||||||
|
target_link_libraries(gtest_main PUBLIC gtest)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
#
|
#
|
||||||
# Install rules
|
# Install rules
|
||||||
install(TARGETS gtest gtest_main
|
install_project(gtest gtest_main)
|
||||||
DESTINATION lib)
|
|
||||||
install(DIRECTORY ${gtest_SOURCE_DIR}/include/gtest
|
|
||||||
DESTINATION include)
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
#
|
#
|
||||||
|
@ -147,33 +190,34 @@ if (gtest_build_tests)
|
||||||
############################################################
|
############################################################
|
||||||
# C++ tests built with standard compiler flags.
|
# C++ tests built with standard compiler flags.
|
||||||
|
|
||||||
cxx_test(gtest-death-test_test gtest_main)
|
cxx_test(googletest-death-test-test gtest_main)
|
||||||
cxx_test(gtest_environment_test gtest)
|
cxx_test(gtest_environment_test gtest)
|
||||||
cxx_test(gtest-filepath_test gtest_main)
|
cxx_test(googletest-filepath-test gtest_main)
|
||||||
cxx_test(gtest-linked_ptr_test gtest_main)
|
cxx_test(googletest-listener-test gtest_main)
|
||||||
cxx_test(gtest-listener_test gtest_main)
|
|
||||||
cxx_test(gtest_main_unittest gtest_main)
|
cxx_test(gtest_main_unittest gtest_main)
|
||||||
cxx_test(gtest-message_test gtest_main)
|
cxx_test(googletest-message-test gtest_main)
|
||||||
cxx_test(gtest_no_test_unittest gtest)
|
cxx_test(gtest_no_test_unittest gtest)
|
||||||
cxx_test(gtest-options_test gtest_main)
|
cxx_test(googletest-options-test gtest_main)
|
||||||
cxx_test(gtest-param-test_test gtest
|
cxx_test(googletest-param-test-test gtest
|
||||||
test/gtest-param-test2_test.cc)
|
test/googletest-param-test2-test.cc)
|
||||||
cxx_test(gtest-port_test gtest_main)
|
cxx_test(googletest-port-test gtest_main)
|
||||||
cxx_test(gtest_pred_impl_unittest gtest_main)
|
cxx_test(gtest_pred_impl_unittest gtest_main)
|
||||||
cxx_test(gtest_premature_exit_test gtest
|
cxx_test(gtest_premature_exit_test gtest
|
||||||
test/gtest_premature_exit_test.cc)
|
test/gtest_premature_exit_test.cc)
|
||||||
cxx_test(gtest-printers_test gtest_main)
|
cxx_test(googletest-printers-test gtest_main)
|
||||||
cxx_test(gtest_prod_test gtest_main
|
cxx_test(gtest_prod_test gtest_main
|
||||||
test/production.cc)
|
test/production.cc)
|
||||||
cxx_test(gtest_repeat_test gtest)
|
cxx_test(gtest_repeat_test gtest)
|
||||||
cxx_test(gtest_sole_header_test gtest_main)
|
cxx_test(gtest_sole_header_test gtest_main)
|
||||||
cxx_test(gtest_stress_test gtest)
|
cxx_test(gtest_stress_test gtest)
|
||||||
cxx_test(gtest-test-part_test gtest_main)
|
cxx_test(googletest-test-part-test gtest_main)
|
||||||
cxx_test(gtest_throw_on_failure_ex_test gtest)
|
cxx_test(gtest_throw_on_failure_ex_test gtest)
|
||||||
cxx_test(gtest-typed-test_test gtest_main
|
cxx_test(gtest-typed-test_test gtest_main
|
||||||
test/gtest-typed-test2_test.cc)
|
test/gtest-typed-test2_test.cc)
|
||||||
cxx_test(gtest_unittest gtest_main)
|
cxx_test(gtest_unittest gtest_main)
|
||||||
cxx_test(gtest-unittest-api_test gtest)
|
cxx_test(gtest-unittest-api_test gtest)
|
||||||
|
cxx_test(gtest_skip_in_environment_setup_test gtest_main)
|
||||||
|
cxx_test(gtest_skip_test gtest_main)
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
# C++ tests built with non-standard compiler flags.
|
# C++ tests built with non-standard compiler flags.
|
||||||
|
@ -190,10 +234,10 @@ if (gtest_build_tests)
|
||||||
|
|
||||||
cxx_test_with_flags(gtest-death-test_ex_nocatch_test
|
cxx_test_with_flags(gtest-death-test_ex_nocatch_test
|
||||||
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0"
|
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0"
|
||||||
gtest test/gtest-death-test_ex_test.cc)
|
gtest test/googletest-death-test_ex_test.cc)
|
||||||
cxx_test_with_flags(gtest-death-test_ex_catch_test
|
cxx_test_with_flags(gtest-death-test_ex_catch_test
|
||||||
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1"
|
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1"
|
||||||
gtest test/gtest-death-test_ex_test.cc)
|
gtest test/googletest-death-test_ex_test.cc)
|
||||||
|
|
||||||
cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
|
cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
|
||||||
gtest_main_no_rtti test/gtest_unittest.cc)
|
gtest_main_no_rtti test/gtest_unittest.cc)
|
||||||
|
@ -207,80 +251,73 @@ if (gtest_build_tests)
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
|
COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
|
||||||
|
|
||||||
if (NOT MSVC OR MSVC_VERSION LESS 1600) # 1600 is Visual Studio 2010.
|
|
||||||
# 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.
|
|
||||||
cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}"
|
|
||||||
src/gtest-all.cc src/gtest_main.cc)
|
|
||||||
|
|
||||||
cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}"
|
|
||||||
gtest_main_use_own_tuple test/gtest-tuple_test.cc)
|
|
||||||
|
|
||||||
cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}"
|
|
||||||
gtest_main_use_own_tuple
|
|
||||||
test/gtest-param-test_test.cc test/gtest-param-test2_test.cc)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
# Python tests.
|
# Python tests.
|
||||||
|
|
||||||
cxx_executable(gtest_break_on_failure_unittest_ test gtest)
|
cxx_executable(googletest-break-on-failure-unittest_ test gtest)
|
||||||
py_test(gtest_break_on_failure_unittest)
|
py_test(googletest-break-on-failure-unittest)
|
||||||
|
|
||||||
|
py_test(gtest_skip_check_output_test)
|
||||||
|
py_test(gtest_skip_environment_check_output_test)
|
||||||
|
|
||||||
# Visual Studio .NET 2003 does not support STL with exceptions disabled.
|
# Visual Studio .NET 2003 does not support STL with exceptions disabled.
|
||||||
if (NOT MSVC OR MSVC_VERSION GREATER 1310) # 1310 is Visual Studio .NET 2003
|
if (NOT MSVC OR MSVC_VERSION GREATER 1310) # 1310 is Visual Studio .NET 2003
|
||||||
cxx_executable_with_flags(
|
cxx_executable_with_flags(
|
||||||
gtest_catch_exceptions_no_ex_test_
|
googletest-catch-exceptions-no-ex-test_
|
||||||
"${cxx_no_exception}"
|
"${cxx_no_exception}"
|
||||||
gtest_main_no_exception
|
gtest_main_no_exception
|
||||||
test/gtest_catch_exceptions_test_.cc)
|
test/googletest-catch-exceptions-test_.cc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
cxx_executable_with_flags(
|
cxx_executable_with_flags(
|
||||||
gtest_catch_exceptions_ex_test_
|
googletest-catch-exceptions-ex-test_
|
||||||
"${cxx_exception}"
|
"${cxx_exception}"
|
||||||
gtest_main
|
gtest_main
|
||||||
test/gtest_catch_exceptions_test_.cc)
|
test/googletest-catch-exceptions-test_.cc)
|
||||||
py_test(gtest_catch_exceptions_test)
|
py_test(googletest-catch-exceptions-test)
|
||||||
|
|
||||||
cxx_executable(gtest_color_test_ test gtest)
|
cxx_executable(googletest-color-test_ test gtest)
|
||||||
py_test(gtest_color_test)
|
py_test(googletest-color-test)
|
||||||
|
|
||||||
cxx_executable(gtest_env_var_test_ test gtest)
|
cxx_executable(googletest-env-var-test_ test gtest)
|
||||||
py_test(gtest_env_var_test)
|
py_test(googletest-env-var-test)
|
||||||
|
|
||||||
cxx_executable(gtest_filter_unittest_ test gtest)
|
cxx_executable(googletest-filter-unittest_ test gtest)
|
||||||
py_test(gtest_filter_unittest)
|
py_test(googletest-filter-unittest)
|
||||||
|
|
||||||
cxx_executable(gtest_help_test_ test gtest_main)
|
cxx_executable(gtest_help_test_ test gtest_main)
|
||||||
py_test(gtest_help_test)
|
py_test(gtest_help_test)
|
||||||
|
|
||||||
cxx_executable(gtest_list_tests_unittest_ test gtest)
|
cxx_executable(googletest-list-tests-unittest_ test gtest)
|
||||||
py_test(gtest_list_tests_unittest)
|
py_test(googletest-list-tests-unittest)
|
||||||
|
|
||||||
cxx_executable(gtest_output_test_ test gtest)
|
cxx_executable(googletest-output-test_ test gtest)
|
||||||
py_test(gtest_output_test)
|
py_test(googletest-output-test --no_stacktrace_support)
|
||||||
|
|
||||||
cxx_executable(gtest_shuffle_test_ test gtest)
|
cxx_executable(googletest-shuffle-test_ test gtest)
|
||||||
py_test(gtest_shuffle_test)
|
py_test(googletest-shuffle-test)
|
||||||
|
|
||||||
# MSVC 7.1 does not support STL with exceptions disabled.
|
# MSVC 7.1 does not support STL with exceptions disabled.
|
||||||
if (NOT MSVC OR MSVC_VERSION GREATER 1310)
|
if (NOT MSVC OR MSVC_VERSION GREATER 1310)
|
||||||
cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception)
|
cxx_executable(googletest-throw-on-failure-test_ test gtest_no_exception)
|
||||||
set_target_properties(gtest_throw_on_failure_test_
|
set_target_properties(googletest-throw-on-failure-test_
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
COMPILE_FLAGS "${cxx_no_exception}")
|
COMPILE_FLAGS "${cxx_no_exception}")
|
||||||
py_test(gtest_throw_on_failure_test)
|
py_test(googletest-throw-on-failure-test)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
cxx_executable(gtest_uninitialized_test_ test gtest)
|
cxx_executable(googletest-uninitialized-test_ test gtest)
|
||||||
py_test(gtest_uninitialized_test)
|
py_test(googletest-uninitialized-test)
|
||||||
|
|
||||||
|
cxx_executable(gtest_list_output_unittest_ test gtest)
|
||||||
|
py_test(gtest_list_output_unittest)
|
||||||
|
|
||||||
cxx_executable(gtest_xml_outfile1_test_ test gtest_main)
|
cxx_executable(gtest_xml_outfile1_test_ test gtest_main)
|
||||||
cxx_executable(gtest_xml_outfile2_test_ test gtest_main)
|
cxx_executable(gtest_xml_outfile2_test_ test gtest_main)
|
||||||
py_test(gtest_xml_outfiles_test)
|
py_test(gtest_xml_outfiles_test)
|
||||||
|
py_test(googletest-json-outfiles-test)
|
||||||
|
|
||||||
cxx_executable(gtest_xml_output_unittest_ test gtest)
|
cxx_executable(gtest_xml_output_unittest_ test gtest)
|
||||||
py_test(gtest_xml_output_unittest)
|
py_test(gtest_xml_output_unittest --no_stacktrace_support)
|
||||||
|
py_test(googletest-json-output-unittest --no_stacktrace_support)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,181 +1,156 @@
|
||||||
|
### Generic Build Instructions
|
||||||
|
|
||||||
### Generic Build Instructions ###
|
#### Setup
|
||||||
|
|
||||||
#### Setup ####
|
To build GoogleTest and your tests that use it, you need to tell your build
|
||||||
|
system where to find its headers and source files. The exact way to do it
|
||||||
|
depends on which build system you use, and is usually straightforward.
|
||||||
|
|
||||||
To build Google Test and your tests that use it, you need to tell your
|
### Build with CMake
|
||||||
build system where to find its headers and source files. The exact
|
|
||||||
way to do it depends on which build system you use, and is usually
|
|
||||||
straightforward.
|
|
||||||
|
|
||||||
#### Build ####
|
GoogleTest comes with a CMake build script
|
||||||
|
([CMakeLists.txt](https://github.com/google/googletest/blob/master/CMakeLists.txt))
|
||||||
|
that can be used on a wide range of platforms ("C" stands for cross-platform.).
|
||||||
|
If you don't have CMake installed already, you can download it for free from
|
||||||
|
<http://www.cmake.org/>.
|
||||||
|
|
||||||
Suppose you put Google Test in directory `${GTEST_DIR}`. To build it,
|
CMake works by generating native makefiles or build projects that can be used in
|
||||||
create a library build target (or a project as called by Visual Studio
|
the compiler environment of your choice. You can either build GoogleTest as a
|
||||||
and Xcode) to compile
|
standalone project or it can be incorporated into an existing CMake build for
|
||||||
|
another project.
|
||||||
|
|
||||||
${GTEST_DIR}/src/gtest-all.cc
|
#### Standalone CMake Project
|
||||||
|
|
||||||
with `${GTEST_DIR}/include` in the system header search path and `${GTEST_DIR}`
|
When building GoogleTest as a standalone project, the typical workflow starts
|
||||||
in the normal header search path. Assuming a Linux-like system and gcc,
|
with
|
||||||
something like the following will do:
|
|
||||||
|
|
||||||
g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
|
```
|
||||||
-pthread -c ${GTEST_DIR}/src/gtest-all.cc
|
git clone https://github.com/google/googletest.git -b release-1.10.0
|
||||||
ar -rv libgtest.a gtest-all.o
|
cd googletest # Main directory of the cloned repository.
|
||||||
|
mkdir build # Create a directory to hold the build output.
|
||||||
|
cd build
|
||||||
|
cmake .. # Generate native build scripts for GoogleTest.
|
||||||
|
```
|
||||||
|
|
||||||
(We need `-pthread` as Google Test uses threads.)
|
The above command also includes GoogleMock by default. And so, if you want to
|
||||||
|
build only GoogleTest, you should replace the last command with
|
||||||
|
|
||||||
Next, you should compile your test source file with
|
```
|
||||||
`${GTEST_DIR}/include` in the system header search path, and link it
|
cmake .. -DBUILD_GMOCK=OFF
|
||||||
with gtest and any other necessary libraries:
|
```
|
||||||
|
|
||||||
g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \
|
If you are on a \*nix system, you should now see a Makefile in the current
|
||||||
-o your_test
|
directory. Just type `make` to build GoogleTest. And then you can simply install
|
||||||
|
GoogleTest if you are a system administrator.
|
||||||
|
|
||||||
As an example, the make/ directory contains a Makefile that you can
|
```
|
||||||
use to build Google Test on systems where GNU make is available
|
make
|
||||||
(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
|
sudo make install # Install in /usr/local/ by default
|
||||||
Test's own tests. Instead, it just builds the Google Test library and
|
```
|
||||||
a sample test. You can use it as a starting point for your own build
|
|
||||||
script.
|
|
||||||
|
|
||||||
If the default settings are correct for your environment, the
|
If you use Windows and have Visual Studio installed, a `gtest.sln` file and
|
||||||
following commands should succeed:
|
several `.vcproj` files will be created. You can then build them using Visual
|
||||||
|
Studio.
|
||||||
cd ${GTEST_DIR}/make
|
|
||||||
make
|
|
||||||
./sample1_unittest
|
|
||||||
|
|
||||||
If you see errors, try to tweak the contents of `make/Makefile` to make
|
|
||||||
them go away. There are instructions in `make/Makefile` on how to do
|
|
||||||
it.
|
|
||||||
|
|
||||||
### Using CMake ###
|
|
||||||
|
|
||||||
Google Test comes with a CMake build script (
|
|
||||||
[CMakeLists.txt](CMakeLists.txt)) that can be used on a wide range of platforms ("C" stands for
|
|
||||||
cross-platform.). If you don't have CMake installed already, you can
|
|
||||||
download it for free from <http://www.cmake.org/>.
|
|
||||||
|
|
||||||
CMake works by generating native makefiles or build projects that can
|
|
||||||
be used in the compiler environment of your choice. The typical
|
|
||||||
workflow starts with:
|
|
||||||
|
|
||||||
mkdir mybuild # Create a directory to hold the build output.
|
|
||||||
cd mybuild
|
|
||||||
cmake ${GTEST_DIR} # Generate native build scripts.
|
|
||||||
|
|
||||||
If you want to build Google Test's samples, you should replace the
|
|
||||||
last command with
|
|
||||||
|
|
||||||
cmake -Dgtest_build_samples=ON ${GTEST_DIR}
|
|
||||||
|
|
||||||
If you are on a \*nix system, you should now see a Makefile in the
|
|
||||||
current directory. Just type 'make' to build gtest.
|
|
||||||
|
|
||||||
If you use Windows and have Visual Studio installed, a `gtest.sln` file
|
|
||||||
and several `.vcproj` files will be created. You can then build them
|
|
||||||
using Visual Studio.
|
|
||||||
|
|
||||||
On Mac OS X with Xcode installed, a `.xcodeproj` file will be generated.
|
On Mac OS X with Xcode installed, a `.xcodeproj` file will be generated.
|
||||||
|
|
||||||
### Legacy Build Scripts ###
|
#### Incorporating Into An Existing CMake Project
|
||||||
|
|
||||||
Before settling on CMake, we have been providing hand-maintained build
|
If you want to use GoogleTest in a project which already uses CMake, the easiest
|
||||||
projects/scripts for Visual Studio, Xcode, and Autotools. While we
|
way is to get installed libraries and headers.
|
||||||
continue to provide them for convenience, they are not actively
|
|
||||||
maintained any more. We highly recommend that you follow the
|
|
||||||
instructions in the previous two sections to integrate Google Test
|
|
||||||
with your existing build system.
|
|
||||||
|
|
||||||
If you still need to use the legacy build scripts, here's how:
|
* Import GoogleTest by using `find_package` (or `pkg_check_modules`). For
|
||||||
|
example, if `find_package(GTest CONFIG REQUIRED)` succeeds, you can use the
|
||||||
|
libraries as `GTest::gtest`, `GTest::gmock`.
|
||||||
|
|
||||||
The msvc\ folder contains two solutions with Visual C++ projects.
|
And a more robust and flexible approach is to build GoogleTest as part of that
|
||||||
Open the `gtest.sln` or `gtest-md.sln` file using Visual Studio, and you
|
project directly. This is done by making the GoogleTest source code available to
|
||||||
are ready to build Google Test the same way you build any Visual
|
the main build and adding it using CMake's `add_subdirectory()` command. This
|
||||||
Studio project. Files that have names ending with -md use DLL
|
has the significant advantage that the same compiler and linker settings are
|
||||||
versions of Microsoft runtime libraries (the /MD or the /MDd compiler
|
used between GoogleTest and the rest of your project, so issues associated with
|
||||||
option). Files without that suffix use static versions of the runtime
|
using incompatible libraries (eg debug/release), etc. are avoided. This is
|
||||||
libraries (the /MT or the /MTd option). Please note that one must use
|
particularly useful on Windows. Making GoogleTest's source code available to the
|
||||||
the same option to compile both gtest and the test code. If you use
|
main build can be done a few different ways:
|
||||||
Visual Studio 2005 or above, we recommend the -md version as /MD is
|
|
||||||
the default for new projects in these versions of Visual Studio.
|
|
||||||
|
|
||||||
On Mac OS X, open the `gtest.xcodeproj` in the `xcode/` folder using
|
* Download the GoogleTest source code manually and place it at a known
|
||||||
Xcode. Build the "gtest" target. The universal binary framework will
|
location. This is the least flexible approach and can make it more difficult
|
||||||
end up in your selected build directory (selected in the Xcode
|
to use with continuous integration systems, etc.
|
||||||
"Preferences..." -> "Building" pane and defaults to xcode/build).
|
* Embed the GoogleTest source code as a direct copy in the main project's
|
||||||
Alternatively, at the command line, enter:
|
source tree. This is often the simplest approach, but is also the hardest to
|
||||||
|
keep up to date. Some organizations may not permit this method.
|
||||||
|
* Add GoogleTest as a git submodule or equivalent. This may not always be
|
||||||
|
possible or appropriate. Git submodules, for example, have their own set of
|
||||||
|
advantages and drawbacks.
|
||||||
|
* Use CMake to download GoogleTest as part of the build's configure step. This
|
||||||
|
approach doesn't have the limitations of the other methods.
|
||||||
|
|
||||||
xcodebuild
|
The last of the above methods is implemented with a small piece of CMake code
|
||||||
|
that downloads and pulls the GoogleTest code into the main build.
|
||||||
|
|
||||||
This will build the "Release" configuration of gtest.framework in your
|
Just add to your `CMakeLists.txt`:
|
||||||
default build location. See the "xcodebuild" man page for more
|
|
||||||
information about building different configurations and building in
|
|
||||||
different locations.
|
|
||||||
|
|
||||||
If you wish to use the Google Test Xcode project with Xcode 4.x and
|
```cmake
|
||||||
above, you need to either:
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
googletest
|
||||||
|
# Specify the commit you depend on and update it regularly.
|
||||||
|
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
|
||||||
|
)
|
||||||
|
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
||||||
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
FetchContent_MakeAvailable(googletest)
|
||||||
|
|
||||||
* update the SDK configuration options in xcode/Config/General.xconfig.
|
# Now simply link against gtest or gtest_main as needed. Eg
|
||||||
Comment options `SDKROOT`, `MACOS_DEPLOYMENT_TARGET`, and `GCC_VERSION`. If
|
add_executable(example example.cpp)
|
||||||
you choose this route you lose the ability to target earlier versions
|
target_link_libraries(example gtest_main)
|
||||||
of MacOS X.
|
add_test(NAME example_test COMMAND example)
|
||||||
* Install an SDK for an earlier version. This doesn't appear to be
|
```
|
||||||
supported by Apple, but has been reported to work
|
|
||||||
(http://stackoverflow.com/questions/5378518).
|
|
||||||
|
|
||||||
### Tweaking Google Test ###
|
Note that this approach requires CMake 3.14 or later due to its use of the
|
||||||
|
`FetchContent_MakeAvailable()` command.
|
||||||
|
|
||||||
Google Test can be used in diverse environments. The default
|
##### Visual Studio Dynamic vs Static Runtimes
|
||||||
configuration may not work (or may not work well) out of the box in
|
|
||||||
some environments. However, you can easily tweak Google Test by
|
|
||||||
defining control macros on the compiler command line. Generally,
|
|
||||||
these macros are named like `GTEST_XYZ` and you define them to either 1
|
|
||||||
or 0 to enable or disable a certain feature.
|
|
||||||
|
|
||||||
We list the most frequently used macros below. For a complete list,
|
By default, new Visual Studio projects link the C runtimes dynamically but
|
||||||
see file [include/gtest/internal/gtest-port.h](include/gtest/internal/gtest-port.h).
|
GoogleTest links them statically. This will generate an error that looks
|
||||||
|
something like the following: gtest.lib(gtest-all.obj) : error LNK2038: mismatch
|
||||||
|
detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value
|
||||||
|
'MDd_DynamicDebug' in main.obj
|
||||||
|
|
||||||
### Choosing a TR1 Tuple Library ###
|
GoogleTest already has a CMake option for this: `gtest_force_shared_crt`
|
||||||
|
|
||||||
Some Google Test features require the C++ Technical Report 1 (TR1)
|
Enabling this option will make gtest link the runtimes dynamically too, and
|
||||||
tuple library, which is not yet available with all compilers. The
|
match the project in which it is included.
|
||||||
good news is that Google Test implements a subset of TR1 tuple that's
|
|
||||||
enough for its own need, and will automatically use this when the
|
|
||||||
compiler doesn't provide TR1 tuple.
|
|
||||||
|
|
||||||
Usually you don't need to care about which tuple library Google Test
|
#### C++ Standard Version
|
||||||
uses. However, if your project already uses TR1 tuple, you need to
|
|
||||||
tell Google Test to use the same TR1 tuple library the rest of your
|
|
||||||
project uses, or the two tuple implementations will clash. To do
|
|
||||||
that, add
|
|
||||||
|
|
||||||
-DGTEST_USE_OWN_TR1_TUPLE=0
|
An environment that supports C++11 is required in order to successfully build
|
||||||
|
GoogleTest. One way to ensure this is to specify the standard in the top-level
|
||||||
|
project, for example by using the `set(CMAKE_CXX_STANDARD 11)` command. If this
|
||||||
|
is not feasible, for example in a C project using GoogleTest for validation,
|
||||||
|
then it can be specified by adding it to the options for cmake via the
|
||||||
|
`DCMAKE_CXX_FLAGS` option.
|
||||||
|
|
||||||
to the compiler flags while compiling Google Test and your tests. If
|
### Tweaking GoogleTest
|
||||||
you want to force Google Test to use its own tuple library, just add
|
|
||||||
|
|
||||||
-DGTEST_USE_OWN_TR1_TUPLE=1
|
GoogleTest can be used in diverse environments. The default configuration may
|
||||||
|
not work (or may not work well) out of the box in some environments. However,
|
||||||
|
you can easily tweak GoogleTest by defining control macros on the compiler
|
||||||
|
command line. Generally, these macros are named like `GTEST_XYZ` and you define
|
||||||
|
them to either 1 or 0 to enable or disable a certain feature.
|
||||||
|
|
||||||
to the compiler flags instead.
|
We list the most frequently used macros below. For a complete list, see file
|
||||||
|
[include/gtest/internal/gtest-port.h](https://github.com/google/googletest/blob/master/googletest/include/gtest/internal/gtest-port.h).
|
||||||
|
|
||||||
If you don't want Google Test to use tuple at all, add
|
### Multi-threaded Tests
|
||||||
|
|
||||||
-DGTEST_HAS_TR1_TUPLE=0
|
GoogleTest is thread-safe where the pthread library is available. After
|
||||||
|
`#include "gtest/gtest.h"`, you can check the
|
||||||
|
`GTEST_IS_THREADSAFE` macro to see whether this is the case (yes if the macro is
|
||||||
|
`#defined` to 1, no if it's undefined.).
|
||||||
|
|
||||||
and all features using tuple will be disabled.
|
If GoogleTest doesn't correctly detect whether pthread is available in your
|
||||||
|
environment, you can force it with
|
||||||
### Multi-threaded Tests ###
|
|
||||||
|
|
||||||
Google Test is thread-safe where the pthread library is available.
|
|
||||||
After `#include "gtest/gtest.h"`, you can check the `GTEST_IS_THREADSAFE`
|
|
||||||
macro to see whether this is the case (yes if the macro is `#defined` to
|
|
||||||
1, no if it's undefined.).
|
|
||||||
|
|
||||||
If Google Test doesn't correctly detect whether pthread is available
|
|
||||||
in your environment, you can force it with
|
|
||||||
|
|
||||||
-DGTEST_HAS_PTHREAD=1
|
-DGTEST_HAS_PTHREAD=1
|
||||||
|
|
||||||
|
@ -183,26 +158,24 @@ or
|
||||||
|
|
||||||
-DGTEST_HAS_PTHREAD=0
|
-DGTEST_HAS_PTHREAD=0
|
||||||
|
|
||||||
When Google Test uses pthread, you may need to add flags to your
|
When GoogleTest uses pthread, you may need to add flags to your compiler and/or
|
||||||
compiler and/or linker to select the pthread library, or you'll get
|
linker to select the pthread library, or you'll get link errors. If you use the
|
||||||
link errors. If you use the CMake script or the deprecated Autotools
|
CMake script, this is taken care of for you. If you use your own build script,
|
||||||
script, this is taken care of for you. If you use your own build
|
you'll need to read your compiler and linker's manual to figure out what flags
|
||||||
script, you'll need to read your compiler and linker's manual to
|
to add.
|
||||||
figure out what flags to add.
|
|
||||||
|
|
||||||
### As a Shared Library (DLL) ###
|
### As a Shared Library (DLL)
|
||||||
|
|
||||||
Google Test is compact, so most users can build and link it as a
|
GoogleTest is compact, so most users can build and link it as a static library
|
||||||
static library for the simplicity. You can choose to use Google Test
|
for the simplicity. You can choose to use GoogleTest as a shared library (known
|
||||||
as a shared library (known as a DLL on Windows) if you prefer.
|
as a DLL on Windows) if you prefer.
|
||||||
|
|
||||||
To compile *gtest* as a shared library, add
|
To compile *gtest* as a shared library, add
|
||||||
|
|
||||||
-DGTEST_CREATE_SHARED_LIBRARY=1
|
-DGTEST_CREATE_SHARED_LIBRARY=1
|
||||||
|
|
||||||
to the compiler flags. You'll also need to tell the linker to produce
|
to the compiler flags. You'll also need to tell the linker to produce a shared
|
||||||
a shared library instead - consult your linker's manual for how to do
|
library instead - consult your linker's manual for how to do it.
|
||||||
it.
|
|
||||||
|
|
||||||
To compile your *tests* that use the gtest shared library, add
|
To compile your *tests* that use the gtest shared library, add
|
||||||
|
|
||||||
|
@ -210,31 +183,28 @@ To compile your *tests* that use the gtest shared library, add
|
||||||
|
|
||||||
to the compiler flags.
|
to the compiler flags.
|
||||||
|
|
||||||
Note: while the above steps aren't technically necessary today when
|
Note: while the above steps aren't technically necessary today when using some
|
||||||
using some compilers (e.g. GCC), they may become necessary in the
|
compilers (e.g. GCC), they may become necessary in the future, if we decide to
|
||||||
future, if we decide to improve the speed of loading the library (see
|
improve the speed of loading the library (see
|
||||||
<http://gcc.gnu.org/wiki/Visibility> for details). Therefore you are
|
<http://gcc.gnu.org/wiki/Visibility> for details). Therefore you are recommended
|
||||||
recommended to always add the above flags when using Google Test as a
|
to always add the above flags when using GoogleTest as a shared library.
|
||||||
shared library. Otherwise a future release of Google Test may break
|
Otherwise a future release of GoogleTest may break your build script.
|
||||||
your build script.
|
|
||||||
|
|
||||||
### Avoiding Macro Name Clashes ###
|
### Avoiding Macro Name Clashes
|
||||||
|
|
||||||
In C++, macros don't obey namespaces. Therefore two libraries that
|
In C++, macros don't obey namespaces. Therefore two libraries that both define a
|
||||||
both define a macro of the same name will clash if you `#include` both
|
macro of the same name will clash if you `#include` both definitions. In case a
|
||||||
definitions. In case a Google Test macro clashes with another
|
GoogleTest macro clashes with another library, you can force GoogleTest to
|
||||||
library, you can force Google Test to rename its macro to avoid the
|
rename its macro to avoid the conflict.
|
||||||
conflict.
|
|
||||||
|
|
||||||
Specifically, if both Google Test and some other code define macro
|
Specifically, if both GoogleTest and some other code define macro FOO, you can
|
||||||
FOO, you can add
|
add
|
||||||
|
|
||||||
-DGTEST_DONT_DEFINE_FOO=1
|
-DGTEST_DONT_DEFINE_FOO=1
|
||||||
|
|
||||||
to the compiler flags to tell Google Test to change the macro's name
|
to the compiler flags to tell GoogleTest to change the macro's name from `FOO`
|
||||||
from `FOO` to `GTEST_FOO`. Currently `FOO` can be `FAIL`, `SUCCEED`,
|
to `GTEST_FOO`. Currently `FOO` can be `FAIL`, `SUCCEED`, or `TEST`. For
|
||||||
or `TEST`. For example, with `-DGTEST_DONT_DEFINE_TEST=1`, you'll
|
example, with `-DGTEST_DONT_DEFINE_TEST=1`, you'll need to write
|
||||||
need to write
|
|
||||||
|
|
||||||
GTEST_TEST(SomeTest, DoesThis) { ... }
|
GTEST_TEST(SomeTest, DoesThis) { ... }
|
||||||
|
|
||||||
|
@ -243,38 +213,3 @@ instead of
|
||||||
TEST(SomeTest, DoesThis) { ... }
|
TEST(SomeTest, DoesThis) { ... }
|
||||||
|
|
||||||
in order to define a test.
|
in order to define a test.
|
||||||
|
|
||||||
## Developing Google Test ##
|
|
||||||
|
|
||||||
This section discusses how to make your own changes to Google Test.
|
|
||||||
|
|
||||||
### Testing Google Test Itself ###
|
|
||||||
|
|
||||||
To make sure your changes work as intended and don't break existing
|
|
||||||
functionality, you'll want to compile and run Google Test's own tests.
|
|
||||||
For that you can use CMake:
|
|
||||||
|
|
||||||
mkdir mybuild
|
|
||||||
cd mybuild
|
|
||||||
cmake -Dgtest_build_tests=ON ${GTEST_DIR}
|
|
||||||
|
|
||||||
Make sure you have Python installed, as some of Google Test's tests
|
|
||||||
are written in Python. If the cmake command complains about not being
|
|
||||||
able to find Python (`Could NOT find PythonInterp (missing:
|
|
||||||
PYTHON_EXECUTABLE)`), try telling it explicitly where your Python
|
|
||||||
executable can be found:
|
|
||||||
|
|
||||||
cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR}
|
|
||||||
|
|
||||||
Next, you can build Google Test and all of its own tests. On \*nix,
|
|
||||||
this is usually done by 'make'. To run the tests, do
|
|
||||||
|
|
||||||
make test
|
|
||||||
|
|
||||||
All tests should pass.
|
|
||||||
|
|
||||||
Normally you don't need to worry about regenerating the source files,
|
|
||||||
unless you need to modify them. In that case, you should modify the
|
|
||||||
corresponding .pump files instead and run the pump.py Python script to
|
|
||||||
regenerate them. You can find pump.py in the [scripts/](scripts/) directory.
|
|
||||||
Read the [Pump manual](docs/PumpManual.md) for how to use it.
|
|
||||||
|
|
|
@ -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@")
|
|
@ -0,0 +1,9 @@
|
||||||
|
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||||
|
includedir=@CMAKE_INSTALL_FULL_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@
|
|
@ -0,0 +1,10 @@
|
||||||
|
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||||
|
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: gtest_main
|
||||||
|
Description: GoogleTest (with main() function)
|
||||||
|
Version: @PROJECT_VERSION@
|
||||||
|
URL: https://github.com/google/googletest
|
||||||
|
Requires: gtest = @PROJECT_VERSION@
|
||||||
|
Libs: -L${libdir} -lgtest_main @CMAKE_THREAD_LIBS_INIT@
|
||||||
|
Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@
|
|
@ -12,6 +12,10 @@
|
||||||
# Test and Google Mock's option() definitions, and thus must be
|
# Test and Google Mock's option() definitions, and thus must be
|
||||||
# called *after* the options have been defined.
|
# 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.
|
# 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
|
# This must be a macro(), as inside a function string() can only
|
||||||
|
@ -20,8 +24,10 @@ macro(fix_default_compiler_settings_)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
# For MSVC, CMake sets certain flags to defaults we want to override.
|
# For MSVC, CMake sets certain flags to defaults we want to override.
|
||||||
# This replacement code is taken from sample in the CMake Wiki at
|
# 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
|
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 CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||||
if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt)
|
if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt)
|
||||||
|
@ -38,6 +44,11 @@ macro(fix_default_compiler_settings_)
|
||||||
# We prefer more strict warning checking for building Google Test.
|
# We prefer more strict warning checking for building Google Test.
|
||||||
# Replaces /W3 with /W4 in defaults.
|
# 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()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
@ -46,52 +57,43 @@ endmacro()
|
||||||
# Google Mock. You can tweak these definitions to suit your need. A
|
# Google Mock. You can tweak these definitions to suit your need. A
|
||||||
# variable's value is empty before it's explicitly assigned to.
|
# variable's value is empty before it's explicitly assigned to.
|
||||||
macro(config_compiler_and_linker)
|
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.
|
# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
|
if (CMAKE_USE_PTHREADS_INIT)
|
||||||
|
set(GTEST_HAS_PTHREAD ON)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
fix_default_compiler_settings_()
|
fix_default_compiler_settings_()
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
# Newlines inside flags variables break CMake's NMake generator.
|
# Newlines inside flags variables break CMake's NMake generator.
|
||||||
# TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds.
|
# TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds.
|
||||||
set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J -Zi")
|
set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J")
|
||||||
if (MSVC_VERSION LESS 1400) # 1400 is Visual Studio 2005
|
|
||||||
# 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()
|
|
||||||
if (MSVC_VERSION LESS 1500) # 1500 is Visual Studio 2008
|
|
||||||
# Conditional expression is constant.
|
|
||||||
# When compiling with /W4, we get several instances of C4127
|
|
||||||
# (Conditional expression is constant). In our code, we disable that
|
|
||||||
# warning on a case-by-case basis. However, on Visual Studio 2005,
|
|
||||||
# the warning fires on std::list. Therefore on that compiler and earlier,
|
|
||||||
# we disable the warning project-wide.
|
|
||||||
set(cxx_base_flags "${cxx_base_flags} -wd4127")
|
|
||||||
endif()
|
|
||||||
if (NOT (MSVC_VERSION LESS 1700)) # 1700 is Visual Studio 2012.
|
|
||||||
# Suppress "unreachable code" warning on VS 2012 and later.
|
|
||||||
# http://stackoverflow.com/questions/3232669 explains the issue.
|
|
||||||
set(cxx_base_flags "${cxx_base_flags} -wd4702")
|
|
||||||
endif()
|
|
||||||
if (NOT (MSVC_VERSION GREATER 1900)) # 1900 is Visual Studio 2015
|
|
||||||
# BigObj required for tests.
|
|
||||||
set(cxx_base_flags "${cxx_base_flags} -bigobj")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
|
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_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
|
||||||
set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
|
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-")
|
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")
|
||||||
|
# Ensure MSVC treats source files as UTF-8 encoded.
|
||||||
|
set(cxx_base_flags "${cxx_base_flags} -utf-8")
|
||||||
|
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)
|
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_exception_flags "-fexceptions")
|
||||||
set(cxx_no_exception_flags "-fno-exceptions")
|
set(cxx_no_exception_flags "-fno-exceptions")
|
||||||
# Until version 4.3.2, GCC doesn't define a macro to indicate
|
# Until version 4.3.2, GCC doesn't define a macro to indicate
|
||||||
|
@ -123,19 +125,20 @@ macro(config_compiler_and_linker)
|
||||||
set(cxx_no_rtti_flags "")
|
set(cxx_no_rtti_flags "")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed.
|
# The pthreads library is available and allowed?
|
||||||
set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1")
|
if (DEFINED GTEST_HAS_PTHREAD)
|
||||||
|
set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=1")
|
||||||
else()
|
else()
|
||||||
set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0")
|
set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=0")
|
||||||
endif()
|
endif()
|
||||||
|
set(cxx_base_flags "${cxx_base_flags} ${GTEST_HAS_PTHREAD_MACRO}")
|
||||||
|
|
||||||
# For building gtest's own tests and samples.
|
# 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
|
set(cxx_no_exception
|
||||||
"${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}")
|
"${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}")
|
||||||
set(cxx_default "${cxx_exception}")
|
set(cxx_default "${cxx_exception}")
|
||||||
set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}")
|
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.
|
# For building the gtest libraries.
|
||||||
set(cxx_strict "${cxx_default} ${cxx_strict_flags}")
|
set(cxx_strict "${cxx_default} ${cxx_strict_flags}")
|
||||||
|
@ -147,16 +150,50 @@ function(cxx_library_with_type name type cxx_flags)
|
||||||
# type can be either STATIC or SHARED to denote a static or shared library.
|
# type can be either STATIC or SHARED to denote a static or shared library.
|
||||||
# ARGN refers to additional arguments after 'cxx_flags'.
|
# ARGN refers to additional arguments after 'cxx_flags'.
|
||||||
add_library(${name} ${type} ${ARGN})
|
add_library(${name} ${type} ${ARGN})
|
||||||
|
add_library(${cmake_package_name}::${name} ALIAS ${name})
|
||||||
set_target_properties(${name}
|
set_target_properties(${name}
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
COMPILE_FLAGS "${cxx_flags}")
|
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")
|
if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED")
|
||||||
set_target_properties(${name}
|
set_target_properties(${name}
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1")
|
COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1")
|
||||||
|
if (NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
|
||||||
|
target_compile_definitions(${name} INTERFACE
|
||||||
|
$<INSTALL_INTERFACE:GTEST_LINKED_AS_SHARED_LIBRARY=1>)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if (CMAKE_USE_PTHREADS_INIT)
|
if (DEFINED GTEST_HAS_PTHREAD)
|
||||||
target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT})
|
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()
|
||||||
|
|
||||||
|
if (NOT "${CMAKE_VERSION}" VERSION_LESS "3.8")
|
||||||
|
target_compile_features(${name} PUBLIC cxx_std_11)
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
@ -178,6 +215,10 @@ endfunction()
|
||||||
# is built from the given source files with the given compiler flags.
|
# is built from the given source files with the given compiler flags.
|
||||||
function(cxx_executable_with_flags name cxx_flags libs)
|
function(cxx_executable_with_flags name cxx_flags libs)
|
||||||
add_executable(${name} ${ARGN})
|
add_executable(${name} ${ARGN})
|
||||||
|
if (MSVC)
|
||||||
|
# BigObj required for tests.
|
||||||
|
set(cxx_flags "${cxx_flags} -bigobj")
|
||||||
|
endif()
|
||||||
if (cxx_flags)
|
if (cxx_flags)
|
||||||
set_target_properties(${name}
|
set_target_properties(${name}
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
|
@ -206,7 +247,13 @@ function(cxx_executable name dir libs)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE.
|
# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE.
|
||||||
find_package(PythonInterp)
|
if ("${CMAKE_VERSION}" VERSION_LESS "3.12.0")
|
||||||
|
find_package(PythonInterp)
|
||||||
|
else()
|
||||||
|
find_package(Python COMPONENTS Interpreter)
|
||||||
|
set(PYTHONINTERP_FOUND ${Python_Interpreter_FOUND})
|
||||||
|
set(PYTHON_EXECUTABLE ${Python_EXECUTABLE})
|
||||||
|
endif()
|
||||||
|
|
||||||
# cxx_test_with_flags(name cxx_flags libs srcs...)
|
# cxx_test_with_flags(name cxx_flags libs srcs...)
|
||||||
#
|
#
|
||||||
|
@ -214,7 +261,7 @@ find_package(PythonInterp)
|
||||||
# from the given source files with the given compiler flags.
|
# from the given source files with the given compiler flags.
|
||||||
function(cxx_test_with_flags name cxx_flags libs)
|
function(cxx_test_with_flags name cxx_flags libs)
|
||||||
cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN})
|
cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN})
|
||||||
add_test(${name} ${name})
|
add_test(NAME ${name} COMMAND "$<TARGET_FILE:${name}>")
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# cxx_test(name libs srcs...)
|
# cxx_test(name libs srcs...)
|
||||||
|
@ -232,23 +279,66 @@ endfunction()
|
||||||
# creates a Python test with the given name whose main module is in
|
# creates a Python test with the given name whose main module is in
|
||||||
# test/name.py. It does nothing if Python is not installed.
|
# test/name.py. It does nothing if Python is not installed.
|
||||||
function(py_test name)
|
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)
|
if (PYTHONINTERP_FOUND)
|
||||||
# ${CMAKE_BINARY_DIR} is known at configuration time, so we can
|
if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 3.1)
|
||||||
# directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known
|
if (CMAKE_CONFIGURATION_TYPES)
|
||||||
# only at ctest runtime (by calling ctest -c <Configuration>), so
|
# Multi-configuration build generators as for Visual Studio save
|
||||||
# we have to escape $ to delay variable substitution here.
|
# output in a subdirectory of CMAKE_CURRENT_BINARY_DIR (Debug,
|
||||||
if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.1)
|
# Release etc.), so we have to provide it here.
|
||||||
add_test(
|
add_test(NAME ${name}
|
||||||
NAME ${name}
|
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
|
||||||
|
--build_dir=${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG> ${ARGN})
|
||||||
|
else (CMAKE_CONFIGURATION_TYPES)
|
||||||
|
# Single-configuration build generators like Makefile generators
|
||||||
|
# don't have subdirs below CMAKE_CURRENT_BINARY_DIR.
|
||||||
|
add_test(NAME ${name}
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
|
||||||
|
--build_dir=${CMAKE_CURRENT_BINARY_DIR} ${ARGN})
|
||||||
|
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 <Configuration>), so
|
||||||
|
# we have to escape $ to delay variable substitution here.
|
||||||
|
add_test(NAME ${name}
|
||||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
|
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
|
||||||
--build_dir=${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>)
|
--build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE} ${ARGN})
|
||||||
else (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.1)
|
endif()
|
||||||
add_test(
|
endif(PYTHONINTERP_FOUND)
|
||||||
${name}
|
endfunction()
|
||||||
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
|
|
||||||
--build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE})
|
# install_project(targets...)
|
||||||
endif (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.1)
|
#
|
||||||
|
# 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}/$<$<CONFIG:Debug>:${t_pdb_name_debug}>$<$<NOT:$<CONFIG: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()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
|
@ -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@'
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Content Moved
|
||||||
|
|
||||||
|
We are working on updates to the GoogleTest documentation, which has moved to
|
||||||
|
the top-level [docs](../../docs) directory.
|
|
@ -26,17 +26,17 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
//
|
//
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
// The Google C++ Testing and Mocking Framework (Google Test)
|
||||||
//
|
|
||||||
// The Google C++ Testing Framework (Google Test)
|
|
||||||
//
|
//
|
||||||
// This header file defines the public API for death tests. It is
|
// 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
|
// #included by gtest.h so a user doesn't need to include this
|
||||||
// directly.
|
// directly.
|
||||||
|
// GOOGLETEST_CM0001 DO NOT DELETE
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
||||||
#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
#define GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
||||||
|
|
||||||
#include "gtest/internal/gtest-death-test-internal.h"
|
#include "gtest/internal/gtest-death-test-internal.h"
|
||||||
|
|
||||||
|
@ -97,12 +97,17 @@ GTEST_API_ bool InDeathTestChild();
|
||||||
//
|
//
|
||||||
// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
|
// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
|
||||||
//
|
//
|
||||||
|
// The final parameter to each of these macros is a matcher applied to any data
|
||||||
|
// the sub-process wrote to stderr. For compatibility with existing tests, a
|
||||||
|
// bare string is interpreted as a regular expression matcher.
|
||||||
|
//
|
||||||
// On the regular expressions used in death tests:
|
// On the regular expressions used in death tests:
|
||||||
//
|
//
|
||||||
|
// GOOGLETEST_CM0005 DO NOT DELETE
|
||||||
// On POSIX-compliant systems (*nix), we use the <regex.h> library,
|
// On POSIX-compliant systems (*nix), we use the <regex.h> library,
|
||||||
// which uses the POSIX extended regex syntax.
|
// 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
|
// syntax implemented as part of Google Test. This limited
|
||||||
// implementation should be enough most of the time when writing
|
// implementation should be enough most of the time when writing
|
||||||
// death tests; though it lacks many features you can find in PCRE
|
// death tests; though it lacks many features you can find in PCRE
|
||||||
|
@ -160,29 +165,28 @@ GTEST_API_ bool InDeathTestChild();
|
||||||
// is rarely a problem as people usually don't put the test binary
|
// is rarely a problem as people usually don't put the test binary
|
||||||
// directory in PATH.
|
// 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
|
// Asserts that a given `statement` causes the program to exit, with an
|
||||||
// integer exit status that satisfies predicate, and emitting error output
|
// integer exit status that satisfies `predicate`, and emitting error output
|
||||||
// that matches regex.
|
// that matches `matcher`.
|
||||||
# define ASSERT_EXIT(statement, predicate, regex) \
|
# define ASSERT_EXIT(statement, predicate, matcher) \
|
||||||
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
|
GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_FATAL_FAILURE_)
|
||||||
|
|
||||||
// Like ASSERT_EXIT, but continues on to successive tests in the
|
// 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) \
|
# define EXPECT_EXIT(statement, predicate, matcher) \
|
||||||
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
|
GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_NONFATAL_FAILURE_)
|
||||||
|
|
||||||
// Asserts that a given statement causes the program to exit, either by
|
// Asserts that a given `statement` causes the program to exit, either by
|
||||||
// explicitly exiting with a nonzero exit code or being killed by a
|
// explicitly exiting with a nonzero exit code or being killed by a
|
||||||
// signal, and emitting error output that matches regex.
|
// signal, and emitting error output that matches `matcher`.
|
||||||
# define ASSERT_DEATH(statement, regex) \
|
# define ASSERT_DEATH(statement, matcher) \
|
||||||
ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
|
ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)
|
||||||
|
|
||||||
// Like ASSERT_DEATH, but continues on to successive tests in the
|
// Like `ASSERT_DEATH`, but continues on to successive tests in the
|
||||||
// test case, if any:
|
// test suite, if any:
|
||||||
# define EXPECT_DEATH(statement, regex) \
|
# define EXPECT_DEATH(statement, matcher) \
|
||||||
EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
|
EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)
|
||||||
|
|
||||||
// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
|
// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
|
||||||
|
|
||||||
|
@ -190,17 +194,17 @@ GTEST_API_ bool InDeathTestChild();
|
||||||
class GTEST_API_ ExitedWithCode {
|
class GTEST_API_ ExitedWithCode {
|
||||||
public:
|
public:
|
||||||
explicit ExitedWithCode(int exit_code);
|
explicit ExitedWithCode(int exit_code);
|
||||||
|
ExitedWithCode(const ExitedWithCode&) = default;
|
||||||
|
void operator=(const ExitedWithCode& other) = delete;
|
||||||
bool operator()(int exit_status) const;
|
bool operator()(int exit_status) const;
|
||||||
private:
|
private:
|
||||||
// No implementation - assignment is unsupported.
|
|
||||||
void operator=(const ExitedWithCode& other);
|
|
||||||
|
|
||||||
const int exit_code_;
|
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
|
// Tests that an exit code describes an exit due to termination by a
|
||||||
// given signal.
|
// given signal.
|
||||||
|
// GOOGLETEST_CM0006 DO NOT DELETE
|
||||||
class GTEST_API_ KilledBySignal {
|
class GTEST_API_ KilledBySignal {
|
||||||
public:
|
public:
|
||||||
explicit KilledBySignal(int signum);
|
explicit KilledBySignal(int signum);
|
||||||
|
@ -226,7 +230,7 @@ class GTEST_API_ KilledBySignal {
|
||||||
// return 12;
|
// return 12;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
|
// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) {
|
||||||
// int sideeffect = 0;
|
// int sideeffect = 0;
|
||||||
// // Only asserts in dbg.
|
// // Only asserts in dbg.
|
||||||
// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
|
// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
|
||||||
|
@ -272,6 +276,54 @@ class GTEST_API_ KilledBySignal {
|
||||||
# endif // NDEBUG for EXPECT_DEBUG_DEATH
|
# endif // NDEBUG for EXPECT_DEBUG_DEATH
|
||||||
#endif // GTEST_HAS_DEATH_TEST
|
#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
|
// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
|
||||||
// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
|
// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
|
||||||
// death tests are supported; otherwise they just issue a warning. This is
|
// death tests are supported; otherwise they just issue a warning. This is
|
||||||
|
@ -284,11 +336,11 @@ class GTEST_API_ KilledBySignal {
|
||||||
ASSERT_DEATH(statement, regex)
|
ASSERT_DEATH(statement, regex)
|
||||||
#else
|
#else
|
||||||
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
|
# 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) \
|
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
|
GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
||||||
|
|
|
@ -0,0 +1,930 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
|
||||||
|
#define GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#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 FooMatcherMatcher that implements the matcher interface:
|
||||||
|
// using is_gtest_matcher = void;
|
||||||
|
// bool MatchAndExplain(const T&, std::ostream*);
|
||||||
|
// (MatchResultListener* can also be used instead of std::ostream*)
|
||||||
|
// void DescribeTo(std::ostream*);
|
||||||
|
// void DescribeNegationTo(std::ostream*);
|
||||||
|
//
|
||||||
|
// 2. a factory function that creates a Matcher<T> object from a
|
||||||
|
// FooMatcherMatcher.
|
||||||
|
|
||||||
|
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 <typename T>
|
||||||
|
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 GTEST_API_ 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 <typename T>
|
||||||
|
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 {
|
||||||
|
|
||||||
|
struct AnyEq {
|
||||||
|
template <typename A, typename B>
|
||||||
|
bool operator()(const A& a, const B& b) const { return a == b; }
|
||||||
|
};
|
||||||
|
struct AnyNe {
|
||||||
|
template <typename A, typename B>
|
||||||
|
bool operator()(const A& a, const B& b) const { return a != b; }
|
||||||
|
};
|
||||||
|
struct AnyLt {
|
||||||
|
template <typename A, typename B>
|
||||||
|
bool operator()(const A& a, const B& b) const { return a < b; }
|
||||||
|
};
|
||||||
|
struct AnyGt {
|
||||||
|
template <typename A, typename B>
|
||||||
|
bool operator()(const A& a, const B& b) const { return a > b; }
|
||||||
|
};
|
||||||
|
struct AnyLe {
|
||||||
|
template <typename A, typename B>
|
||||||
|
bool operator()(const A& a, const B& b) const { return a <= b; }
|
||||||
|
};
|
||||||
|
struct AnyGe {
|
||||||
|
template <typename A, typename B>
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SharedPayloadBase {
|
||||||
|
std::atomic<int> ref{1};
|
||||||
|
void Ref() { ref.fetch_add(1, std::memory_order_relaxed); }
|
||||||
|
bool Unref() { return ref.fetch_sub(1, std::memory_order_acq_rel) == 1; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct SharedPayload : SharedPayloadBase {
|
||||||
|
explicit SharedPayload(const T& v) : value(v) {}
|
||||||
|
explicit SharedPayload(T&& v) : value(std::move(v)) {}
|
||||||
|
|
||||||
|
static void Destroy(SharedPayloadBase* shared) {
|
||||||
|
delete static_cast<SharedPayload*>(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// An internal class for implementing Matcher<T>, which will derive
|
||||||
|
// from it. We put functionalities common to all Matcher<T>
|
||||||
|
// specializations here to avoid code duplication.
|
||||||
|
template <typename T>
|
||||||
|
class MatcherBase : private MatcherDescriberInterface {
|
||||||
|
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 {
|
||||||
|
GTEST_CHECK_(vtable_ != nullptr);
|
||||||
|
return vtable_->match_and_explain(*this, 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 final {
|
||||||
|
GTEST_CHECK_(vtable_ != nullptr);
|
||||||
|
vtable_->describe(*this, os, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describes the negation of this matcher to an ostream.
|
||||||
|
void DescribeNegationTo(::std::ostream* os) const final {
|
||||||
|
GTEST_CHECK_(vtable_ != nullptr);
|
||||||
|
vtable_->describe(*this, os, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
if (vtable_ == nullptr) return nullptr;
|
||||||
|
return vtable_->get_describer(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MatcherBase() : vtable_(nullptr) {}
|
||||||
|
|
||||||
|
// Constructs a matcher from its implementation.
|
||||||
|
template <typename U>
|
||||||
|
explicit MatcherBase(const MatcherInterface<U>* impl) {
|
||||||
|
Init(impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename M, typename = typename std::remove_reference<
|
||||||
|
M>::type::is_gtest_matcher>
|
||||||
|
MatcherBase(M&& m) { // NOLINT
|
||||||
|
Init(std::forward<M>(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
MatcherBase(const MatcherBase& other)
|
||||||
|
: vtable_(other.vtable_), buffer_(other.buffer_) {
|
||||||
|
if (IsShared()) buffer_.shared->Ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
MatcherBase& operator=(const MatcherBase& other) {
|
||||||
|
if (this == &other) return *this;
|
||||||
|
Destroy();
|
||||||
|
vtable_ = other.vtable_;
|
||||||
|
buffer_ = other.buffer_;
|
||||||
|
if (IsShared()) buffer_.shared->Ref();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatcherBase(MatcherBase&& other)
|
||||||
|
: vtable_(other.vtable_), buffer_(other.buffer_) {
|
||||||
|
other.vtable_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatcherBase& operator=(MatcherBase&& other) {
|
||||||
|
if (this == &other) return *this;
|
||||||
|
Destroy();
|
||||||
|
vtable_ = other.vtable_;
|
||||||
|
buffer_ = other.buffer_;
|
||||||
|
other.vtable_ = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~MatcherBase() override { Destroy(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct VTable {
|
||||||
|
bool (*match_and_explain)(const MatcherBase&, const T&,
|
||||||
|
MatchResultListener*);
|
||||||
|
void (*describe)(const MatcherBase&, std::ostream*, bool negation);
|
||||||
|
// Returns the captured object if it implements the interface, otherwise
|
||||||
|
// returns the MatcherBase itself.
|
||||||
|
const MatcherDescriberInterface* (*get_describer)(const MatcherBase&);
|
||||||
|
// Called on shared instances when the reference count reaches 0.
|
||||||
|
void (*shared_destroy)(SharedPayloadBase*);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool IsShared() const {
|
||||||
|
return vtable_ != nullptr && vtable_->shared_destroy != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the implementation uses a listener, call that.
|
||||||
|
template <typename P>
|
||||||
|
static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
|
||||||
|
MatchResultListener* listener)
|
||||||
|
-> decltype(P::Get(m).MatchAndExplain(value, listener->stream())) {
|
||||||
|
return P::Get(m).MatchAndExplain(value, listener->stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
|
||||||
|
MatchResultListener* listener)
|
||||||
|
-> decltype(P::Get(m).MatchAndExplain(value, listener)) {
|
||||||
|
return P::Get(m).MatchAndExplain(value, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
static void DescribeImpl(const MatcherBase& m, std::ostream* os,
|
||||||
|
bool negation) {
|
||||||
|
if (negation) {
|
||||||
|
P::Get(m).DescribeNegationTo(os);
|
||||||
|
} else {
|
||||||
|
P::Get(m).DescribeTo(os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
static const MatcherDescriberInterface* GetDescriberImpl(
|
||||||
|
const MatcherBase& m) {
|
||||||
|
// If the impl is a MatcherDescriberInterface, then return it.
|
||||||
|
// Otherwise use MatcherBase itself.
|
||||||
|
// This allows us to implement the GetDescriber() function without support
|
||||||
|
// from the impl, but some users really want to get their impl back when
|
||||||
|
// they call GetDescriber().
|
||||||
|
// We use std::get on a tuple as a workaround of not having `if constexpr`.
|
||||||
|
return std::get<(
|
||||||
|
std::is_convertible<decltype(&P::Get(m)),
|
||||||
|
const MatcherDescriberInterface*>::value
|
||||||
|
? 1
|
||||||
|
: 0)>(std::make_tuple(&m, &P::Get(m)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
const VTable* GetVTable() {
|
||||||
|
static constexpr VTable kVTable = {&MatchAndExplainImpl<P>,
|
||||||
|
&DescribeImpl<P>, &GetDescriberImpl<P>,
|
||||||
|
P::shared_destroy};
|
||||||
|
return &kVTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
union Buffer {
|
||||||
|
// Add some types to give Buffer some common alignment/size use cases.
|
||||||
|
void* ptr;
|
||||||
|
double d;
|
||||||
|
int64_t i;
|
||||||
|
// And add one for the out-of-line cases.
|
||||||
|
SharedPayloadBase* shared;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Destroy() {
|
||||||
|
if (IsShared() && buffer_.shared->Unref()) {
|
||||||
|
vtable_->shared_destroy(buffer_.shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
static constexpr bool IsInlined() {
|
||||||
|
return sizeof(M) <= sizeof(Buffer) && alignof(M) <= alignof(Buffer) &&
|
||||||
|
std::is_trivially_copy_constructible<M>::value &&
|
||||||
|
std::is_trivially_destructible<M>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename M, bool = MatcherBase::IsInlined<M>()>
|
||||||
|
struct ValuePolicy {
|
||||||
|
static const M& Get(const MatcherBase& m) {
|
||||||
|
// When inlined along with Init, need to be explicit to avoid violating
|
||||||
|
// strict aliasing rules.
|
||||||
|
const M *ptr = static_cast<const M*>(
|
||||||
|
static_cast<const void*>(&m.buffer_));
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
static void Init(MatcherBase& m, M impl) {
|
||||||
|
::new (static_cast<void*>(&m.buffer_)) M(impl);
|
||||||
|
}
|
||||||
|
static constexpr auto shared_destroy = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
struct ValuePolicy<M, false> {
|
||||||
|
using Shared = SharedPayload<M>;
|
||||||
|
static const M& Get(const MatcherBase& m) {
|
||||||
|
return static_cast<Shared*>(m.buffer_.shared)->value;
|
||||||
|
}
|
||||||
|
template <typename Arg>
|
||||||
|
static void Init(MatcherBase& m, Arg&& arg) {
|
||||||
|
m.buffer_.shared = new Shared(std::forward<Arg>(arg));
|
||||||
|
}
|
||||||
|
static constexpr auto shared_destroy = &Shared::Destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename U, bool B>
|
||||||
|
struct ValuePolicy<const MatcherInterface<U>*, B> {
|
||||||
|
using M = const MatcherInterface<U>;
|
||||||
|
using Shared = SharedPayload<std::unique_ptr<M>>;
|
||||||
|
static const M& Get(const MatcherBase& m) {
|
||||||
|
return *static_cast<Shared*>(m.buffer_.shared)->value;
|
||||||
|
}
|
||||||
|
static void Init(MatcherBase& m, M* impl) {
|
||||||
|
m.buffer_.shared = new Shared(std::unique_ptr<M>(impl));
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto shared_destroy = &Shared::Destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
void Init(M&& m) {
|
||||||
|
using MM = typename std::decay<M>::type;
|
||||||
|
using Policy = ValuePolicy<MM>;
|
||||||
|
vtable_ = GetVTable<Policy>();
|
||||||
|
Policy::Init(*this, std::forward<M>(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
const VTable* vtable_;
|
||||||
|
Buffer buffer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// A Matcher<T> is a copyable and IMMUTABLE (except by assignment)
|
||||||
|
// object that can check whether a value of type T matches. The
|
||||||
|
// implementation of Matcher<T> is just a std::shared_ptr to const
|
||||||
|
// MatcherInterface<T>. Don't inherit from Matcher!
|
||||||
|
template <typename T>
|
||||||
|
class Matcher : public internal::MatcherBase<T> {
|
||||||
|
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<const T&>* impl)
|
||||||
|
: internal::MatcherBase<T>(impl) {}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
explicit Matcher(
|
||||||
|
const MatcherInterface<U>* impl,
|
||||||
|
typename std::enable_if<!std::is_same<U, const U&>::value>::type* =
|
||||||
|
nullptr)
|
||||||
|
: internal::MatcherBase<T>(impl) {}
|
||||||
|
|
||||||
|
template <typename M, typename = typename std::remove_reference<
|
||||||
|
M>::type::is_gtest_matcher>
|
||||||
|
Matcher(M&& m) : internal::MatcherBase<T>(std::forward<M>(m)) {} // NOLINT
|
||||||
|
|
||||||
|
// 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<const std::string&>
|
||||||
|
: public internal::MatcherBase<const std::string&> {
|
||||||
|
public:
|
||||||
|
Matcher() {}
|
||||||
|
|
||||||
|
explicit Matcher(const MatcherInterface<const std::string&>* impl)
|
||||||
|
: internal::MatcherBase<const std::string&>(impl) {}
|
||||||
|
|
||||||
|
template <typename M, typename = typename std::remove_reference<
|
||||||
|
M>::type::is_gtest_matcher>
|
||||||
|
Matcher(M&& m) // NOLINT
|
||||||
|
: internal::MatcherBase<const std::string&>(std::forward<M>(m)) {}
|
||||||
|
|
||||||
|
// 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<std::string>
|
||||||
|
: public internal::MatcherBase<std::string> {
|
||||||
|
public:
|
||||||
|
Matcher() {}
|
||||||
|
|
||||||
|
explicit Matcher(const MatcherInterface<const std::string&>* impl)
|
||||||
|
: internal::MatcherBase<std::string>(impl) {}
|
||||||
|
explicit Matcher(const MatcherInterface<std::string>* impl)
|
||||||
|
: internal::MatcherBase<std::string>(impl) {}
|
||||||
|
|
||||||
|
template <typename M, typename = typename std::remove_reference<
|
||||||
|
M>::type::is_gtest_matcher>
|
||||||
|
Matcher(M&& m) // NOLINT
|
||||||
|
: internal::MatcherBase<std::string>(std::forward<M>(m)) {}
|
||||||
|
|
||||||
|
// 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_INTERNAL_HAS_STRING_VIEW
|
||||||
|
// 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<const internal::StringView&>
|
||||||
|
: public internal::MatcherBase<const internal::StringView&> {
|
||||||
|
public:
|
||||||
|
Matcher() {}
|
||||||
|
|
||||||
|
explicit Matcher(const MatcherInterface<const internal::StringView&>* impl)
|
||||||
|
: internal::MatcherBase<const internal::StringView&>(impl) {}
|
||||||
|
|
||||||
|
template <typename M, typename = typename std::remove_reference<
|
||||||
|
M>::type::is_gtest_matcher>
|
||||||
|
Matcher(M&& m) // NOLINT
|
||||||
|
: internal::MatcherBase<const internal::StringView&>(std::forward<M>(m)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 or std::string_views directly.
|
||||||
|
Matcher(internal::StringView s); // NOLINT
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class GTEST_API_ Matcher<internal::StringView>
|
||||||
|
: public internal::MatcherBase<internal::StringView> {
|
||||||
|
public:
|
||||||
|
Matcher() {}
|
||||||
|
|
||||||
|
explicit Matcher(const MatcherInterface<const internal::StringView&>* impl)
|
||||||
|
: internal::MatcherBase<internal::StringView>(impl) {}
|
||||||
|
explicit Matcher(const MatcherInterface<internal::StringView>* impl)
|
||||||
|
: internal::MatcherBase<internal::StringView>(impl) {}
|
||||||
|
|
||||||
|
template <typename M, typename = typename std::remove_reference<
|
||||||
|
M>::type::is_gtest_matcher>
|
||||||
|
Matcher(M&& m) // NOLINT
|
||||||
|
: internal::MatcherBase<internal::StringView>(std::forward<M>(m)) {}
|
||||||
|
|
||||||
|
// 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 or std::string_views directly.
|
||||||
|
Matcher(internal::StringView s); // NOLINT
|
||||||
|
};
|
||||||
|
#endif // GTEST_INTERNAL_HAS_STRING_VIEW
|
||||||
|
|
||||||
|
// Prints a matcher in a human-readable format.
|
||||||
|
template <typename T>
|
||||||
|
std::ostream& operator<<(std::ostream& os, const Matcher<T>& 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 Impl>
|
||||||
|
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 <typename T>
|
||||||
|
operator Matcher<T>() const {
|
||||||
|
return Matcher<T>(new MonomorphicImpl<const T&>(impl_));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T>
|
||||||
|
class MonomorphicImpl : public MatcherInterface<T> {
|
||||||
|
public:
|
||||||
|
explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
|
||||||
|
|
||||||
|
void DescribeTo(::std::ostream* os) const override { impl_.DescribeTo(os); }
|
||||||
|
|
||||||
|
void DescribeNegationTo(::std::ostream* os) const override {
|
||||||
|
impl_.DescribeNegationTo(os);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatchAndExplain(T x, MatchResultListener* listener) const override {
|
||||||
|
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<T>(new MyMatcherImpl<const T&>(...));
|
||||||
|
//
|
||||||
|
// MakeMatcher may create a Matcher that accepts its argument by value, which
|
||||||
|
// leads to unnecessary copies & lack of support for non-copyable types.
|
||||||
|
template <typename T>
|
||||||
|
inline Matcher<T> MakeMatcher(const MatcherInterface<T>* impl) {
|
||||||
|
return Matcher<T>(impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a polymorphic matcher from its implementation. This is
|
||||||
|
// easier to use than the PolymorphicMatcher<Impl> constructor as it
|
||||||
|
// doesn't require you to explicitly write the template argument, e.g.
|
||||||
|
//
|
||||||
|
// MakePolymorphicMatcher(foo);
|
||||||
|
// vs
|
||||||
|
// PolymorphicMatcher<TypeOfFoo>(foo);
|
||||||
|
template <class Impl>
|
||||||
|
inline PolymorphicMatcher<Impl> MakePolymorphicMatcher(const Impl& impl) {
|
||||||
|
return PolymorphicMatcher<Impl>(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 <typename D, typename Rhs, typename Op>
|
||||||
|
class ComparisonBase {
|
||||||
|
public:
|
||||||
|
explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {}
|
||||||
|
|
||||||
|
using is_gtest_matcher = void;
|
||||||
|
|
||||||
|
template <typename Lhs>
|
||||||
|
bool MatchAndExplain(const Lhs& lhs, std::ostream*) const {
|
||||||
|
return Op()(lhs, Unwrap(rhs_));
|
||||||
|
}
|
||||||
|
void DescribeTo(std::ostream* os) const {
|
||||||
|
*os << D::Desc() << " ";
|
||||||
|
UniversalPrint(Unwrap(rhs_), os);
|
||||||
|
}
|
||||||
|
void DescribeNegationTo(std::ostream* os) const {
|
||||||
|
*os << D::NegatedDesc() << " ";
|
||||||
|
UniversalPrint(Unwrap(rhs_), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T>
|
||||||
|
static const T& Unwrap(const T& v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
static const T& Unwrap(std::reference_wrapper<T> v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rhs rhs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Rhs>
|
||||||
|
class EqMatcher : public ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq> {
|
||||||
|
public:
|
||||||
|
explicit EqMatcher(const Rhs& rhs)
|
||||||
|
: ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq>(rhs) { }
|
||||||
|
static const char* Desc() { return "is equal to"; }
|
||||||
|
static const char* NegatedDesc() { return "isn't equal to"; }
|
||||||
|
};
|
||||||
|
template <typename Rhs>
|
||||||
|
class NeMatcher : public ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe> {
|
||||||
|
public:
|
||||||
|
explicit NeMatcher(const Rhs& rhs)
|
||||||
|
: ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe>(rhs) { }
|
||||||
|
static const char* Desc() { return "isn't equal to"; }
|
||||||
|
static const char* NegatedDesc() { return "is equal to"; }
|
||||||
|
};
|
||||||
|
template <typename Rhs>
|
||||||
|
class LtMatcher : public ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt> {
|
||||||
|
public:
|
||||||
|
explicit LtMatcher(const Rhs& rhs)
|
||||||
|
: ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt>(rhs) { }
|
||||||
|
static const char* Desc() { return "is <"; }
|
||||||
|
static const char* NegatedDesc() { return "isn't <"; }
|
||||||
|
};
|
||||||
|
template <typename Rhs>
|
||||||
|
class GtMatcher : public ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt> {
|
||||||
|
public:
|
||||||
|
explicit GtMatcher(const Rhs& rhs)
|
||||||
|
: ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt>(rhs) { }
|
||||||
|
static const char* Desc() { return "is >"; }
|
||||||
|
static const char* NegatedDesc() { return "isn't >"; }
|
||||||
|
};
|
||||||
|
template <typename Rhs>
|
||||||
|
class LeMatcher : public ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe> {
|
||||||
|
public:
|
||||||
|
explicit LeMatcher(const Rhs& rhs)
|
||||||
|
: ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe>(rhs) { }
|
||||||
|
static const char* Desc() { return "is <="; }
|
||||||
|
static const char* NegatedDesc() { return "isn't <="; }
|
||||||
|
};
|
||||||
|
template <typename Rhs>
|
||||||
|
class GeMatcher : public ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe> {
|
||||||
|
public:
|
||||||
|
explicit GeMatcher(const Rhs& rhs)
|
||||||
|
: ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe>(rhs) { }
|
||||||
|
static const char* Desc() { return "is >="; }
|
||||||
|
static const char* NegatedDesc() { return "isn't >="; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename = typename std::enable_if<
|
||||||
|
std::is_constructible<std::string, T>::value>::type>
|
||||||
|
using StringLike = T;
|
||||||
|
|
||||||
|
// Implements polymorphic matchers MatchesRegex(regex) and
|
||||||
|
// ContainsRegex(regex), which can be used as a Matcher<T> 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_INTERNAL_HAS_STRING_VIEW
|
||||||
|
bool MatchAndExplain(const internal::StringView& s,
|
||||||
|
MatchResultListener* listener) const {
|
||||||
|
return MatchAndExplain(std::string(s), listener);
|
||||||
|
}
|
||||||
|
#endif // GTEST_INTERNAL_HAS_STRING_VIEW
|
||||||
|
|
||||||
|
// Accepts pointer types, particularly:
|
||||||
|
// const char*
|
||||||
|
// char*
|
||||||
|
// const wchar_t*
|
||||||
|
// wchar_t*
|
||||||
|
template <typename CharType>
|
||||||
|
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 <class MatcheeStringType>
|
||||||
|
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<std::string>::Print(regex_->pattern(), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescribeNegationTo(::std::ostream* os) const {
|
||||||
|
*os << "doesn't " << (full_match_ ? "match" : "contain")
|
||||||
|
<< " regular expression ";
|
||||||
|
UniversalPrinter<std::string>::Print(regex_->pattern(), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::shared_ptr<const RE> regex_;
|
||||||
|
const bool full_match_;
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// Matches a string that fully matches regular expression 'regex'.
|
||||||
|
// The matcher takes ownership of 'regex'.
|
||||||
|
inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
|
||||||
|
const internal::RE* regex) {
|
||||||
|
return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
|
||||||
|
}
|
||||||
|
template <typename T = std::string>
|
||||||
|
PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
|
||||||
|
const internal::StringLike<T>& regex) {
|
||||||
|
return MatchesRegex(new internal::RE(std::string(regex)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches a string that contains regular expression 'regex'.
|
||||||
|
// The matcher takes ownership of 'regex'.
|
||||||
|
inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
|
||||||
|
const internal::RE* regex) {
|
||||||
|
return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
|
||||||
|
}
|
||||||
|
template <typename T = std::string>
|
||||||
|
PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
|
||||||
|
const internal::StringLike<T>& regex) {
|
||||||
|
return ContainsRegex(new internal::RE(std::string(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 <typename T>
|
||||||
|
inline internal::EqMatcher<T> Eq(T x) { return internal::EqMatcher<T>(x); }
|
||||||
|
|
||||||
|
// Constructs a Matcher<T> from a 'value' of type T. The constructed
|
||||||
|
// matcher matches any value that's equal to 'value'.
|
||||||
|
template <typename T>
|
||||||
|
Matcher<T>::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<T>(x) is just a convenient short-hand for Matcher<T>(Eq(x))
|
||||||
|
// or Matcher<T>(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<T>(Lt(5)) to be explicit about the type,
|
||||||
|
// for example.
|
||||||
|
template <typename Lhs, typename Rhs>
|
||||||
|
inline Matcher<Lhs> TypedEq(const Rhs& rhs) { return Eq(rhs); }
|
||||||
|
|
||||||
|
// Creates a polymorphic matcher that matches anything >= x.
|
||||||
|
template <typename Rhs>
|
||||||
|
inline internal::GeMatcher<Rhs> Ge(Rhs x) {
|
||||||
|
return internal::GeMatcher<Rhs>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a polymorphic matcher that matches anything > x.
|
||||||
|
template <typename Rhs>
|
||||||
|
inline internal::GtMatcher<Rhs> Gt(Rhs x) {
|
||||||
|
return internal::GtMatcher<Rhs>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a polymorphic matcher that matches anything <= x.
|
||||||
|
template <typename Rhs>
|
||||||
|
inline internal::LeMatcher<Rhs> Le(Rhs x) {
|
||||||
|
return internal::LeMatcher<Rhs>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a polymorphic matcher that matches anything < x.
|
||||||
|
template <typename Rhs>
|
||||||
|
inline internal::LtMatcher<Rhs> Lt(Rhs x) {
|
||||||
|
return internal::LtMatcher<Rhs>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a polymorphic matcher that matches anything != x.
|
||||||
|
template <typename Rhs>
|
||||||
|
inline internal::NeMatcher<Rhs> Ne(Rhs x) {
|
||||||
|
return internal::NeMatcher<Rhs>(x);
|
||||||
|
}
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046
|
||||||
|
|
||||||
|
#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
|
|
@ -26,10 +26,9 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
//
|
//
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
// The Google C++ Testing and Mocking Framework (Google Test)
|
||||||
//
|
|
||||||
// The Google C++ Testing Framework (Google Test)
|
|
||||||
//
|
//
|
||||||
// This header file defines the Message class.
|
// This header file defines the Message class.
|
||||||
//
|
//
|
||||||
|
@ -43,13 +42,20 @@
|
||||||
// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
|
// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
|
||||||
// program!
|
// program!
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
// GOOGLETEST_CM0001 DO NOT DELETE
|
||||||
#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
|
||||||
|
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||||
|
#define GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "gtest/internal/gtest-port.h"
|
#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.
|
// Ensures that there is at least one operator<< in the global namespace.
|
||||||
// See Message& operator<<(...) below for why.
|
// See Message& operator<<(...) below for why.
|
||||||
void operator<<(const testing::internal::Secret&, int);
|
void operator<<(const testing::internal::Secret&, int);
|
||||||
|
@ -102,14 +108,6 @@ class GTEST_API_ Message {
|
||||||
*ss_ << str;
|
*ss_ << str;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GTEST_OS_SYMBIAN
|
|
||||||
// Streams a value (either a pointer or not) to this object.
|
|
||||||
template <typename T>
|
|
||||||
inline Message& operator <<(const T& value) {
|
|
||||||
StreamHelper(typename internal::is_pointer<T>::type(), value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// Streams a non-pointer value to this object.
|
// Streams a non-pointer value to this object.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline Message& operator <<(const T& val) {
|
inline Message& operator <<(const T& val) {
|
||||||
|
@ -147,14 +145,13 @@ class GTEST_API_ Message {
|
||||||
// as "(null)".
|
// as "(null)".
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline Message& operator <<(T* const& pointer) { // NOLINT
|
inline Message& operator <<(T* const& pointer) { // NOLINT
|
||||||
if (pointer == NULL) {
|
if (pointer == nullptr) {
|
||||||
*ss_ << "(null)";
|
*ss_ << "(null)";
|
||||||
} else {
|
} else {
|
||||||
*ss_ << pointer;
|
*ss_ << pointer;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif // GTEST_OS_SYMBIAN
|
|
||||||
|
|
||||||
// Since the basic IO manipulators are overloaded for both narrow
|
// Since the basic IO manipulators are overloaded for both narrow
|
||||||
// and wide streams, we have to provide this specialized definition
|
// and wide streams, we have to provide this specialized definition
|
||||||
|
@ -183,12 +180,6 @@ class GTEST_API_ Message {
|
||||||
Message& operator <<(const ::std::wstring& wstr);
|
Message& operator <<(const ::std::wstring& wstr);
|
||||||
#endif // GTEST_HAS_STD_WSTRING
|
#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.
|
// Gets the text streamed to this object so far as an std::string.
|
||||||
// Each '\0' character in the buffer is replaced with "\\0".
|
// Each '\0' character in the buffer is replaced with "\\0".
|
||||||
//
|
//
|
||||||
|
@ -196,32 +187,8 @@ class GTEST_API_ Message {
|
||||||
std::string GetString() const;
|
std::string GetString() const;
|
||||||
|
|
||||||
private:
|
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 <typename T>
|
|
||||||
inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) {
|
|
||||||
if (pointer == NULL) {
|
|
||||||
*ss_ << "(null)";
|
|
||||||
} else {
|
|
||||||
*ss_ << pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template <typename T>
|
|
||||||
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.
|
// 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
|
// We declare (but don't implement) this to prevent the compiler
|
||||||
// from implementing the assignment operator.
|
// from implementing the assignment operator.
|
||||||
|
@ -247,4 +214,6 @@ std::string StreamableToString(const T& streamable) {
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
|
||||||
|
|
||||||
|
#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -26,17 +26,21 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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
|
// Utilities for testing Google Test itself and code that uses Google Test
|
||||||
// (e.g. frameworks built on top of Google Test).
|
// (e.g. frameworks built on top of Google Test).
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
// GOOGLETEST_CM0004 DO NOT DELETE
|
||||||
#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
|
||||||
|
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
|
||||||
|
#define GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
|
||||||
|
|
||||||
#include "gtest/gtest.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 {
|
namespace testing {
|
||||||
|
|
||||||
// This helper class can be used to mock out Google Test failure reporting
|
// This helper class can be used to mock out Google Test failure reporting
|
||||||
|
@ -68,14 +72,15 @@ class GTEST_API_ ScopedFakeTestPartResultReporter
|
||||||
TestPartResultArray* result);
|
TestPartResultArray* result);
|
||||||
|
|
||||||
// The d'tor restores the previous test part result reporter.
|
// The d'tor restores the previous test part result reporter.
|
||||||
virtual ~ScopedFakeTestPartResultReporter();
|
~ScopedFakeTestPartResultReporter() override;
|
||||||
|
|
||||||
// Appends the TestPartResult object to the TestPartResultArray
|
// Appends the TestPartResult object to the TestPartResultArray
|
||||||
// received in the constructor.
|
// received in the constructor.
|
||||||
//
|
//
|
||||||
// This method is from the TestPartResultReporterInterface
|
// This method is from the TestPartResultReporterInterface
|
||||||
// interface.
|
// interface.
|
||||||
virtual void ReportTestPartResult(const TestPartResult& result);
|
void ReportTestPartResult(const TestPartResult& result) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
|
@ -97,13 +102,12 @@ class GTEST_API_ SingleFailureChecker {
|
||||||
public:
|
public:
|
||||||
// The constructor remembers the arguments.
|
// The constructor remembers the arguments.
|
||||||
SingleFailureChecker(const TestPartResultArray* results,
|
SingleFailureChecker(const TestPartResultArray* results,
|
||||||
TestPartResult::Type type,
|
TestPartResult::Type type, const std::string& substr);
|
||||||
const string& substr);
|
|
||||||
~SingleFailureChecker();
|
~SingleFailureChecker();
|
||||||
private:
|
private:
|
||||||
const TestPartResultArray* const results_;
|
const TestPartResultArray* const results_;
|
||||||
const TestPartResult::Type type_;
|
const TestPartResult::Type type_;
|
||||||
const string substr_;
|
const std::string substr_;
|
||||||
|
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
|
||||||
};
|
};
|
||||||
|
@ -112,6 +116,8 @@ class GTEST_API_ SingleFailureChecker {
|
||||||
|
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
|
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
|
||||||
|
|
||||||
// A set of macros for testing Google Test assertions or code that's expected
|
// 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
|
// to generate Google Test fatal failures. It verifies that the given
|
||||||
// statement will cause exactly one fatal Google Test failure with 'substr'
|
// statement will cause exactly one fatal Google Test failure with 'substr'
|
||||||
|
@ -229,4 +235,4 @@ class GTEST_API_ SingleFailureChecker {
|
||||||
}\
|
}\
|
||||||
} while (::testing::internal::AlwaysFalse())
|
} while (::testing::internal::AlwaysFalse())
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
|
||||||
|
|
|
@ -27,17 +27,19 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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_
|
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
||||||
#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
#define GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "gtest/internal/gtest-internal.h"
|
#include "gtest/internal/gtest-internal.h"
|
||||||
#include "gtest/internal/gtest-string.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 testing {
|
||||||
|
|
||||||
// A copyable object representing the result of a test part (i.e. an
|
// A copyable object representing the result of a test part (i.e. an
|
||||||
|
@ -51,22 +53,20 @@ class GTEST_API_ TestPartResult {
|
||||||
enum Type {
|
enum Type {
|
||||||
kSuccess, // Succeeded.
|
kSuccess, // Succeeded.
|
||||||
kNonFatalFailure, // Failed but the test can continue.
|
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.
|
// C'tor. TestPartResult does NOT have a default constructor.
|
||||||
// Always use this constructor (with parameters) to create a
|
// Always use this constructor (with parameters) to create a
|
||||||
// TestPartResult object.
|
// TestPartResult object.
|
||||||
TestPartResult(Type a_type,
|
TestPartResult(Type a_type, const char* a_file_name, int a_line_number,
|
||||||
const char* a_file_name,
|
|
||||||
int a_line_number,
|
|
||||||
const char* a_message)
|
const char* a_message)
|
||||||
: type_(a_type),
|
: 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),
|
line_number_(a_line_number),
|
||||||
summary_(ExtractSummary(a_message)),
|
summary_(ExtractSummary(a_message)),
|
||||||
message_(a_message) {
|
message_(a_message) {}
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the outcome of the test part.
|
// Gets the outcome of the test part.
|
||||||
Type type() const { return type_; }
|
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
|
// Gets the name of the source file where the test part took place, or
|
||||||
// NULL if it's unknown.
|
// NULL if it's unknown.
|
||||||
const char* file_name() const {
|
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,
|
// 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.
|
// Gets the message associated with the test part.
|
||||||
const char* message() const { return message_.c_str(); }
|
const char* message() const { return message_.c_str(); }
|
||||||
|
|
||||||
// Returns true iff the test part passed.
|
// Returns true if and only if the test part was skipped.
|
||||||
|
bool skipped() const { return type_ == kSkip; }
|
||||||
|
|
||||||
|
// Returns true if and only if the test part passed.
|
||||||
bool passed() const { return type_ == kSuccess; }
|
bool passed() const { return type_ == kSuccess; }
|
||||||
|
|
||||||
// Returns true iff the test part failed.
|
// Returns true if and only if the test part non-fatally failed.
|
||||||
bool failed() const { return type_ != kSuccess; }
|
|
||||||
|
|
||||||
// Returns true iff the test part non-fatally failed.
|
|
||||||
bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
|
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; }
|
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:
|
private:
|
||||||
Type type_;
|
Type type_;
|
||||||
|
|
||||||
|
@ -143,7 +146,7 @@ class GTEST_API_ TestPartResultArray {
|
||||||
};
|
};
|
||||||
|
|
||||||
// This interface knows how to report a test part result.
|
// This interface knows how to report a test part result.
|
||||||
class TestPartResultReporterInterface {
|
class GTEST_API_ TestPartResultReporterInterface {
|
||||||
public:
|
public:
|
||||||
virtual ~TestPartResultReporterInterface() {}
|
virtual ~TestPartResultReporterInterface() {}
|
||||||
|
|
||||||
|
@ -162,8 +165,8 @@ class GTEST_API_ HasNewFatalFailureHelper
|
||||||
: public TestPartResultReporterInterface {
|
: public TestPartResultReporterInterface {
|
||||||
public:
|
public:
|
||||||
HasNewFatalFailureHelper();
|
HasNewFatalFailureHelper();
|
||||||
virtual ~HasNewFatalFailureHelper();
|
~HasNewFatalFailureHelper() override;
|
||||||
virtual void ReportTestPartResult(const TestPartResult& result);
|
void ReportTestPartResult(const TestPartResult& result) override;
|
||||||
bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
|
bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
|
||||||
private:
|
private:
|
||||||
bool has_new_fatal_failure_;
|
bool has_new_fatal_failure_;
|
||||||
|
@ -176,4 +179,6 @@ class GTEST_API_ HasNewFatalFailureHelper
|
||||||
|
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
|
||||||
|
|
||||||
|
#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
||||||
|
|
|
@ -26,11 +26,11 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
// GOOGLETEST_CM0001 DO NOT DELETE
|
||||||
#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
|
||||||
|
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
||||||
|
#define GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
||||||
|
|
||||||
// This header implements typed tests and type-parameterized tests.
|
// This header implements typed tests and type-parameterized tests.
|
||||||
|
|
||||||
|
@ -51,22 +51,22 @@ class FooTest : public testing::Test {
|
||||||
T value_;
|
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
|
// repeated for each type in the list. The typedef is necessary for
|
||||||
// the macro to parse correctly.
|
// the macro to parse correctly.
|
||||||
typedef testing::Types<char, int, unsigned int> MyTypes;
|
typedef testing::Types<char, int, unsigned int> MyTypes;
|
||||||
TYPED_TEST_CASE(FooTest, MyTypes);
|
TYPED_TEST_SUITE(FooTest, MyTypes);
|
||||||
|
|
||||||
// If the type list contains only one type, you can write that type
|
// If the type list contains only one type, you can write that type
|
||||||
// directly without Types<...>:
|
// 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
|
// 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) {
|
TYPED_TEST(FooTest, DoesBlah) {
|
||||||
// Inside a test, refer to TypeParam to get the type parameter.
|
// Inside a test, refer to the special name TypeParam to get the type
|
||||||
// Since we are inside a derived class template, C++ requires use to
|
// parameter. Since we are inside a derived class template, C++ requires
|
||||||
// visit the members of FooTest via 'this'.
|
// us to visit the members of FooTest via 'this'.
|
||||||
TypeParam n = this->value_;
|
TypeParam n = this->value_;
|
||||||
|
|
||||||
// To visit static members of the fixture, add the TestFixture::
|
// To visit static members of the fixture, add the TestFixture::
|
||||||
|
@ -82,6 +82,24 @@ TYPED_TEST(FooTest, DoesBlah) {
|
||||||
|
|
||||||
TYPED_TEST(FooTest, HasPropertyA) { ... }
|
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 <typename T>
|
||||||
|
// static std::string GetName(int) {
|
||||||
|
// if (std::is_same<T, char>()) return "char";
|
||||||
|
// if (std::is_same<T, int>()) return "int";
|
||||||
|
// if (std::is_same<T, unsigned int>()) return "unsignedInt";
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames);
|
||||||
|
|
||||||
#endif // 0
|
#endif // 0
|
||||||
|
|
||||||
// Type-parameterized tests are abstract test patterns parameterized
|
// Type-parameterized tests are abstract test patterns parameterized
|
||||||
|
@ -107,13 +125,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
|
// (the _P suffix is for "parameterized" or "pattern", whichever you
|
||||||
// prefer):
|
// prefer):
|
||||||
TYPED_TEST_CASE_P(FooTest);
|
TYPED_TEST_SUITE_P(FooTest);
|
||||||
|
|
||||||
// Then, use TYPED_TEST_P() to define as many type-parameterized tests
|
// 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) {
|
TYPED_TEST_P(FooTest, DoesBlah) {
|
||||||
// Inside a test, refer to TypeParam to get the type parameter.
|
// Inside a test, refer to TypeParam to get the type parameter.
|
||||||
TypeParam n = 0;
|
TypeParam n = 0;
|
||||||
|
@ -124,10 +142,10 @@ TYPED_TEST_P(FooTest, HasPropertyA) { ... }
|
||||||
|
|
||||||
// Now the tricky part: you need to register all test patterns before
|
// Now the tricky part: you need to register all test patterns before
|
||||||
// you can instantiate them. The first argument of the macro is the
|
// 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.
|
// case.
|
||||||
REGISTER_TYPED_TEST_CASE_P(FooTest,
|
REGISTER_TYPED_TEST_SUITE_P(FooTest,
|
||||||
DoesBlah, HasPropertyA);
|
DoesBlah, HasPropertyA);
|
||||||
|
|
||||||
// Finally, you are free to instantiate the pattern with the types you
|
// 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
|
// want. If you put the above code in a header file, you can #include
|
||||||
|
@ -135,129 +153,177 @@ REGISTER_TYPED_TEST_CASE_P(FooTest,
|
||||||
//
|
//
|
||||||
// To distinguish different instances of the pattern, the first
|
// To distinguish different instances of the pattern, the first
|
||||||
// argument to the INSTANTIATE_* macro is a prefix that will be added
|
// 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.
|
// different instances.
|
||||||
typedef testing::Types<char, int, unsigned int> MyTypes;
|
typedef testing::Types<char, int, unsigned int> 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
|
// If the type list contains only one type, you can write that type
|
||||||
// directly without Types<...>:
|
// 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
|
#endif // 0
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-internal.h"
|
||||||
#include "gtest/internal/gtest-port.h"
|
#include "gtest/internal/gtest-port.h"
|
||||||
#include "gtest/internal/gtest-type-util.h"
|
#include "gtest/internal/gtest-type-util.h"
|
||||||
|
|
||||||
// Implements typed tests.
|
// Implements typed tests.
|
||||||
|
|
||||||
#if GTEST_HAS_TYPED_TEST
|
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
//
|
//
|
||||||
// Expands to the name of the typedef for the type parameters of the
|
// Expands to the name of the typedef for the type parameters of the
|
||||||
// given test case.
|
// given test suite.
|
||||||
# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
|
#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_
|
||||||
|
|
||||||
// The 'Types' template argument below must have spaces around it
|
// Expands to the name of the typedef for the NameGenerator, responsible for
|
||||||
// since some compilers may choke on '>>' when passing a template
|
// creating the suffixes of the name.
|
||||||
// instance (e.g. Types<int>)
|
#define GTEST_NAME_GENERATOR_(TestSuiteName) \
|
||||||
# define TYPED_TEST_CASE(CaseName, Types) \
|
gtest_type_params_##TestSuiteName##_NameGenerator
|
||||||
typedef ::testing::internal::TypeList< Types >::type \
|
|
||||||
GTEST_TYPE_PARAMS_(CaseName)
|
|
||||||
|
|
||||||
# define TYPED_TEST(CaseName, TestName) \
|
#define TYPED_TEST_SUITE(CaseName, Types, ...) \
|
||||||
template <typename gtest_TypeParam_> \
|
typedef ::testing::internal::GenerateTypeList<Types>::type \
|
||||||
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
|
GTEST_TYPE_PARAMS_(CaseName); \
|
||||||
: public CaseName<gtest_TypeParam_> { \
|
typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \
|
||||||
private: \
|
GTEST_NAME_GENERATOR_(CaseName)
|
||||||
typedef CaseName<gtest_TypeParam_> 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(\
|
|
||||||
"", ::testing::internal::CodeLocation(__FILE__, __LINE__), \
|
|
||||||
#CaseName, #TestName, 0); \
|
|
||||||
template <typename gtest_TypeParam_> \
|
|
||||||
void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
|
|
||||||
|
|
||||||
#endif // GTEST_HAS_TYPED_TEST
|
#define TYPED_TEST(CaseName, TestName) \
|
||||||
|
static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \
|
||||||
|
"test-name must not be empty"); \
|
||||||
|
template <typename gtest_TypeParam_> \
|
||||||
|
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
|
||||||
|
: public CaseName<gtest_TypeParam_> { \
|
||||||
|
private: \
|
||||||
|
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
||||||
|
typedef gtest_TypeParam_ TypeParam; \
|
||||||
|
void TestBody() override; \
|
||||||
|
}; \
|
||||||
|
static 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("", \
|
||||||
|
::testing::internal::CodeLocation( \
|
||||||
|
__FILE__, __LINE__), \
|
||||||
|
GTEST_STRINGIFY_(CaseName), \
|
||||||
|
GTEST_STRINGIFY_(TestName), 0, \
|
||||||
|
::testing::internal::GenerateNames< \
|
||||||
|
GTEST_NAME_GENERATOR_(CaseName), \
|
||||||
|
GTEST_TYPE_PARAMS_(CaseName)>()); \
|
||||||
|
template <typename gtest_TypeParam_> \
|
||||||
|
void GTEST_TEST_CLASS_NAME_(CaseName, \
|
||||||
|
TestName)<gtest_TypeParam_>::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_
|
||||||
|
|
||||||
// Implements type-parameterized tests.
|
// Implements type-parameterized tests.
|
||||||
|
|
||||||
#if GTEST_HAS_TYPED_TEST_P
|
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
//
|
//
|
||||||
// Expands to the namespace name that the type-parameterized tests for
|
// 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.
|
// name of the namespace is subject to change without notice.
|
||||||
# define GTEST_CASE_NAMESPACE_(TestCaseName) \
|
#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_
|
||||||
gtest_case_##TestCaseName##_
|
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
//
|
//
|
||||||
// Expands to the name of the variable used to remember the names of
|
// Expands to the name of the variable used to remember the names of
|
||||||
// the defined tests in the given test case.
|
// the defined tests in the given test suite.
|
||||||
# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
|
#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \
|
||||||
gtest_typed_test_case_p_state_##TestCaseName##_
|
gtest_typed_test_suite_p_state_##TestSuiteName##_
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
|
||||||
//
|
//
|
||||||
// Expands to the name of the variable used to remember the names of
|
// Expands to the name of the variable used to remember the names of
|
||||||
// the registered tests in the given test case.
|
// the registered tests in the given test suite.
|
||||||
# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
|
#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \
|
||||||
gtest_registered_test_names_##TestCaseName##_
|
gtest_registered_test_names_##TestSuiteName##_
|
||||||
|
|
||||||
// The variables defined in the type-parameterized test macros are
|
// The variables defined in the type-parameterized test macros are
|
||||||
// static as typically these macros are used in a .h file that can be
|
// static as typically these macros are used in a .h file that can be
|
||||||
// #included in multiple translation units linked together.
|
// #included in multiple translation units linked together.
|
||||||
# define TYPED_TEST_CASE_P(CaseName) \
|
#define TYPED_TEST_SUITE_P(SuiteName) \
|
||||||
static ::testing::internal::TypedTestCasePState \
|
static ::testing::internal::TypedTestSuitePState \
|
||||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
|
GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName)
|
||||||
|
|
||||||
# define TYPED_TEST_P(CaseName, TestName) \
|
// Legacy API is deprecated but still available
|
||||||
namespace GTEST_CASE_NAMESPACE_(CaseName) { \
|
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
template <typename gtest_TypeParam_> \
|
#define TYPED_TEST_CASE_P \
|
||||||
class TestName : public CaseName<gtest_TypeParam_> { \
|
static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \
|
||||||
private: \
|
TYPED_TEST_SUITE_P
|
||||||
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
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 <typename gtest_TypeParam_> \
|
|
||||||
void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
|
|
||||||
|
|
||||||
# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
|
#define TYPED_TEST_P(SuiteName, TestName) \
|
||||||
namespace GTEST_CASE_NAMESPACE_(CaseName) { \
|
namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
|
||||||
typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
|
template <typename gtest_TypeParam_> \
|
||||||
} \
|
class TestName : public SuiteName<gtest_TypeParam_> { \
|
||||||
static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
|
private: \
|
||||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
|
typedef SuiteName<gtest_TypeParam_> TestFixture; \
|
||||||
__FILE__, __LINE__, #__VA_ARGS__)
|
typedef gtest_TypeParam_ TypeParam; \
|
||||||
|
void TestBody() override; \
|
||||||
|
}; \
|
||||||
|
static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
|
||||||
|
GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \
|
||||||
|
__FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \
|
||||||
|
GTEST_STRINGIFY_(TestName)); \
|
||||||
|
} \
|
||||||
|
template <typename gtest_TypeParam_> \
|
||||||
|
void GTEST_SUITE_NAMESPACE_( \
|
||||||
|
SuiteName)::TestName<gtest_TypeParam_>::TestBody()
|
||||||
|
|
||||||
// The 'Types' template argument below must have spaces around it
|
// Note: this won't work correctly if the trailing arguments are macros.
|
||||||
// since some compilers may choke on '>>' when passing a template
|
#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \
|
||||||
// instance (e.g. Types<int>)
|
namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
|
||||||
# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
|
typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \
|
||||||
bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
|
} \
|
||||||
::testing::internal::TypeParameterizedTestCase<CaseName, \
|
static const char* const GTEST_REGISTERED_TEST_NAMES_( \
|
||||||
GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
|
SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \
|
||||||
::testing::internal::TypeList< Types >::type>::Register(\
|
GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \
|
||||||
#Prefix, \
|
GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__)
|
||||||
::testing::internal::CodeLocation(__FILE__, __LINE__), \
|
|
||||||
>EST_TYPED_TEST_CASE_P_STATE_(CaseName), \
|
|
||||||
#CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
|
|
||||||
|
|
||||||
#endif // GTEST_HAS_TYPED_TEST_P
|
// 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_
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \
|
||||||
|
static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \
|
||||||
|
"test-suit-prefix must not be empty"); \
|
||||||
|
static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \
|
||||||
|
::testing::internal::TypeParameterizedTestSuite< \
|
||||||
|
SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \
|
||||||
|
::testing::internal::GenerateTypeList<Types>::type>:: \
|
||||||
|
Register(GTEST_STRINGIFY_(Prefix), \
|
||||||
|
::testing::internal::CodeLocation(__FILE__, __LINE__), \
|
||||||
|
>EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \
|
||||||
|
GTEST_STRINGIFY_(SuiteName), \
|
||||||
|
GTEST_REGISTERED_TEST_NAMES_(SuiteName), \
|
||||||
|
::testing::internal::GenerateNames< \
|
||||||
|
::testing::internal::NameGeneratorSelector< \
|
||||||
|
__VA_ARGS__>::type, \
|
||||||
|
::testing::internal::GenerateTypeList<Types>::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 // GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -27,18 +27,18 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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!
|
// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
|
||||||
//
|
//
|
||||||
// Implements a family of generic predicate assertion macros.
|
// Implements a family of generic predicate assertion macros.
|
||||||
|
// GOOGLETEST_CM0001 DO NOT DELETE
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||||
#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||||
|
|
||||||
// Makes sure this header is not included before gtest.h.
|
#include "gtest/gtest.h"
|
||||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
|
|
||||||
# error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
|
namespace testing {
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
|
|
||||||
|
|
||||||
// This header implements a family of generic predicate assertion
|
// This header implements a family of generic predicate assertion
|
||||||
// macros:
|
// macros:
|
||||||
|
@ -90,9 +90,10 @@ AssertionResult AssertPred1Helper(const char* pred_text,
|
||||||
const T1& v1) {
|
const T1& v1) {
|
||||||
if (pred(v1)) return AssertionSuccess();
|
if (pred(v1)) return AssertionSuccess();
|
||||||
|
|
||||||
return AssertionFailure() << pred_text << "("
|
return AssertionFailure()
|
||||||
<< e1 << ") evaluates to false, where"
|
<< pred_text << "(" << e1 << ") evaluates to false, where"
|
||||||
<< "\n" << e1 << " evaluates to " << v1;
|
<< "\n"
|
||||||
|
<< e1 << " evaluates to " << ::testing::PrintToString(v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
|
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
|
||||||
|
@ -134,11 +135,12 @@ AssertionResult AssertPred2Helper(const char* pred_text,
|
||||||
const T2& v2) {
|
const T2& v2) {
|
||||||
if (pred(v1, v2)) return AssertionSuccess();
|
if (pred(v1, v2)) return AssertionSuccess();
|
||||||
|
|
||||||
return AssertionFailure() << pred_text << "("
|
return AssertionFailure()
|
||||||
<< e1 << ", "
|
<< pred_text << "(" << e1 << ", " << e2
|
||||||
<< e2 << ") evaluates to false, where"
|
<< ") evaluates to false, where"
|
||||||
<< "\n" << e1 << " evaluates to " << v1
|
<< "\n"
|
||||||
<< "\n" << e2 << " evaluates to " << v2;
|
<< e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
|
||||||
|
<< e2 << " evaluates to " << ::testing::PrintToString(v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
|
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
|
||||||
|
@ -185,13 +187,13 @@ AssertionResult AssertPred3Helper(const char* pred_text,
|
||||||
const T3& v3) {
|
const T3& v3) {
|
||||||
if (pred(v1, v2, v3)) return AssertionSuccess();
|
if (pred(v1, v2, v3)) return AssertionSuccess();
|
||||||
|
|
||||||
return AssertionFailure() << pred_text << "("
|
return AssertionFailure()
|
||||||
<< e1 << ", "
|
<< pred_text << "(" << e1 << ", " << e2 << ", " << e3
|
||||||
<< e2 << ", "
|
<< ") evaluates to false, where"
|
||||||
<< e3 << ") evaluates to false, where"
|
<< "\n"
|
||||||
<< "\n" << e1 << " evaluates to " << v1
|
<< e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
|
||||||
<< "\n" << e2 << " evaluates to " << v2
|
<< e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
|
||||||
<< "\n" << e3 << " evaluates to " << v3;
|
<< e3 << " evaluates to " << ::testing::PrintToString(v3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
|
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
|
||||||
|
@ -243,15 +245,14 @@ AssertionResult AssertPred4Helper(const char* pred_text,
|
||||||
const T4& v4) {
|
const T4& v4) {
|
||||||
if (pred(v1, v2, v3, v4)) return AssertionSuccess();
|
if (pred(v1, v2, v3, v4)) return AssertionSuccess();
|
||||||
|
|
||||||
return AssertionFailure() << pred_text << "("
|
return AssertionFailure()
|
||||||
<< e1 << ", "
|
<< pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4
|
||||||
<< e2 << ", "
|
<< ") evaluates to false, where"
|
||||||
<< e3 << ", "
|
<< "\n"
|
||||||
<< e4 << ") evaluates to false, where"
|
<< e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
|
||||||
<< "\n" << e1 << " evaluates to " << v1
|
<< e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
|
||||||
<< "\n" << e2 << " evaluates to " << v2
|
<< e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n"
|
||||||
<< "\n" << e3 << " evaluates to " << v3
|
<< e4 << " evaluates to " << ::testing::PrintToString(v4);
|
||||||
<< "\n" << e4 << " evaluates to " << v4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
|
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
|
||||||
|
@ -308,17 +309,15 @@ AssertionResult AssertPred5Helper(const char* pred_text,
|
||||||
const T5& v5) {
|
const T5& v5) {
|
||||||
if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
|
if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
|
||||||
|
|
||||||
return AssertionFailure() << pred_text << "("
|
return AssertionFailure()
|
||||||
<< e1 << ", "
|
<< pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4
|
||||||
<< e2 << ", "
|
<< ", " << e5 << ") evaluates to false, where"
|
||||||
<< e3 << ", "
|
<< "\n"
|
||||||
<< e4 << ", "
|
<< e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
|
||||||
<< e5 << ") evaluates to false, where"
|
<< e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
|
||||||
<< "\n" << e1 << " evaluates to " << v1
|
<< e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n"
|
||||||
<< "\n" << e2 << " evaluates to " << v2
|
<< e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n"
|
||||||
<< "\n" << e3 << " evaluates to " << v3
|
<< e5 << " evaluates to " << ::testing::PrintToString(v5);
|
||||||
<< "\n" << e4 << " evaluates to " << v4
|
|
||||||
<< "\n" << e5 << " evaluates to " << v5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
|
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
|
||||||
|
@ -355,4 +354,6 @@ AssertionResult AssertPred5Helper(const char* pred_text,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||||
|
|
|
@ -26,13 +26,13 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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.
|
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
//
|
||||||
#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
// Google C++ Testing and Mocking Framework definitions useful in production code.
|
||||||
|
// GOOGLETEST_CM0003 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
|
||||||
|
#define GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
|
||||||
|
|
||||||
// When you need to test the private or protected members of a class,
|
// When you need to test the private or protected members of a class,
|
||||||
// use the FRIEND_TEST macro to declare your tests as friends of the
|
// use the FRIEND_TEST macro to declare your tests as friends of the
|
||||||
|
@ -40,19 +40,22 @@
|
||||||
//
|
//
|
||||||
// class MyClass {
|
// class MyClass {
|
||||||
// private:
|
// private:
|
||||||
// void MyMethod();
|
// void PrivateMethod();
|
||||||
// FRIEND_TEST(MyClassTest, MyMethod);
|
// FRIEND_TEST(MyClassTest, PrivateMethodWorks);
|
||||||
// };
|
// };
|
||||||
//
|
//
|
||||||
// class MyClassTest : public testing::Test {
|
// class MyClassTest : public testing::Test {
|
||||||
// // ...
|
// // ...
|
||||||
// };
|
// };
|
||||||
//
|
//
|
||||||
// TEST_F(MyClassTest, MyMethod) {
|
// TEST_F(MyClassTest, PrivateMethodWorks) {
|
||||||
// // Can call MyClass::MyMethod() here.
|
// // 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)\
|
#define FRIEND_TEST(test_case_name, test_name)\
|
||||||
friend class test_case_name##_##test_name##_Test
|
friend class test_case_name##_##test_name##_Test
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
|
||||||
|
|
|
@ -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.
|
|
@ -27,43 +27,11 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
// Injection point for custom user configurations.
|
// Injection point for custom user configurations. See README for details
|
||||||
// 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)
|
|
||||||
//
|
|
||||||
// Test filtering:
|
|
||||||
// GTEST_TEST_FILTER_ENV_VAR_ - The name of an environment variable that
|
|
||||||
// will be used if --GTEST_FLAG(test_filter)
|
|
||||||
// is not provided.
|
|
||||||
//
|
|
||||||
// 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)
|
|
||||||
//
|
//
|
||||||
// ** Custom implementation starts here **
|
// ** Custom implementation starts here **
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
|
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
|
||||||
#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
|
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
|
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
|
||||||
|
|
|
@ -31,12 +31,12 @@
|
||||||
// installation of gTest.
|
// installation of gTest.
|
||||||
// It will be included from gtest-printers.h and the overrides in this file
|
// It will be included from gtest-printers.h and the overrides in this file
|
||||||
// will be visible to everyone.
|
// will be visible to everyone.
|
||||||
// See documentation at gtest/gtest-printers.h for details on how to define a
|
//
|
||||||
// custom printer.
|
// Injection point for custom user configurations. See README for details
|
||||||
//
|
//
|
||||||
// ** Custom implementation starts here **
|
// ** Custom implementation starts here **
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
|
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
|
||||||
#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
|
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
|
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
|
||||||
|
|
|
@ -27,15 +27,11 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
// Injection point for custom user configurations.
|
// Injection point for custom user configurations. See README for details
|
||||||
// The following macros can be defined:
|
|
||||||
//
|
|
||||||
// GTEST_OS_STACK_TRACE_GETTER_ - The name of an implementation of
|
|
||||||
// OsStackTraceGetterInterface.
|
|
||||||
//
|
//
|
||||||
// ** Custom implementation starts here **
|
// ** Custom implementation starts here **
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
|
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
|
||||||
#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
|
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
|
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
|
||||||
|
|
|
@ -27,19 +27,20 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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 and Mocking Framework (Google Test)
|
||||||
//
|
|
||||||
// The Google C++ Testing Framework (Google Test)
|
|
||||||
//
|
//
|
||||||
// This header file defines internal utilities needed for implementing
|
// This header file defines internal utilities needed for implementing
|
||||||
// death tests. They are subject to change without notice.
|
// death tests. They are subject to change without notice.
|
||||||
|
// GOOGLETEST_CM0001 DO NOT DELETE
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||||
|
|
||||||
|
#include "gtest/gtest-matchers.h"
|
||||||
#include "gtest/internal/gtest-internal.h"
|
#include "gtest/internal/gtest-internal.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -53,6 +54,9 @@ const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
|
||||||
|
|
||||||
#if GTEST_HAS_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
|
// DeathTest is a class that hides much of the complexity of the
|
||||||
// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
|
// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
|
||||||
// returns a concrete class that depends on the prevailing death test
|
// 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
|
// 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
|
// 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.
|
// 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<const std::string&> matcher,
|
||||||
const char* file, int line, DeathTest** test);
|
const char* file, int line, DeathTest** test);
|
||||||
DeathTest();
|
DeathTest();
|
||||||
virtual ~DeathTest() { }
|
virtual ~DeathTest() { }
|
||||||
|
@ -136,25 +140,50 @@ class GTEST_API_ DeathTest {
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
|
||||||
|
|
||||||
// Factory interface for death tests. May be mocked out for testing.
|
// Factory interface for death tests. May be mocked out for testing.
|
||||||
class DeathTestFactory {
|
class DeathTestFactory {
|
||||||
public:
|
public:
|
||||||
virtual ~DeathTestFactory() { }
|
virtual ~DeathTestFactory() { }
|
||||||
virtual bool Create(const char* statement, const RE* regex,
|
virtual bool Create(const char* statement,
|
||||||
const char* file, int line, DeathTest** test) = 0;
|
Matcher<const std::string&> matcher, const char* file,
|
||||||
|
int line, DeathTest** test) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A concrete DeathTestFactory implementation for normal use.
|
// A concrete DeathTestFactory implementation for normal use.
|
||||||
class DefaultDeathTestFactory : public DeathTestFactory {
|
class DefaultDeathTestFactory : public DeathTestFactory {
|
||||||
public:
|
public:
|
||||||
virtual bool Create(const char* statement, const RE* regex,
|
bool Create(const char* statement, Matcher<const std::string&> matcher,
|
||||||
const char* file, int line, DeathTest** test);
|
const char* file, int line, DeathTest** test) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns true if exit_status describes a process that was terminated
|
// Returns true if exit_status describes a process that was terminated
|
||||||
// by a signal, or exited normally with a nonzero exit code.
|
// by a signal, or exited normally with a nonzero exit code.
|
||||||
GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
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<const ::std::string&> MakeDeathTestMatcher(
|
||||||
|
::testing::internal::RE regex) {
|
||||||
|
return ContainsRegex(regex.pattern());
|
||||||
|
}
|
||||||
|
inline Matcher<const ::std::string&> MakeDeathTestMatcher(const char* regex) {
|
||||||
|
return ContainsRegex(regex);
|
||||||
|
}
|
||||||
|
inline Matcher<const ::std::string&> MakeDeathTestMatcher(
|
||||||
|
const ::std::string& regex) {
|
||||||
|
return ContainsRegex(regex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a Matcher<const ::std::string&> is passed to EXPECT_DEATH (etc.), it's
|
||||||
|
// used directly.
|
||||||
|
inline Matcher<const ::std::string&> MakeDeathTestMatcher(
|
||||||
|
Matcher<const ::std::string&> matcher) {
|
||||||
|
return matcher;
|
||||||
|
}
|
||||||
|
|
||||||
// Traps C++ exceptions escaping statement and reports them as test
|
// Traps C++ exceptions escaping statement and reports them as test
|
||||||
// failures. Note that trapping SEH exceptions is not implemented here.
|
// failures. Note that trapping SEH exceptions is not implemented here.
|
||||||
# if GTEST_HAS_EXCEPTIONS
|
# if GTEST_HAS_EXCEPTIONS
|
||||||
|
@ -182,50 +211,53 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
||||||
|
|
||||||
// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
|
// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
|
||||||
// ASSERT_EXIT*, and EXPECT_EXIT*.
|
// ASSERT_EXIT*, and EXPECT_EXIT*.
|
||||||
# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
|
#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \
|
||||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||||
if (::testing::internal::AlwaysTrue()) { \
|
if (::testing::internal::AlwaysTrue()) { \
|
||||||
const ::testing::internal::RE& gtest_regex = (regex); \
|
::testing::internal::DeathTest* gtest_dt; \
|
||||||
::testing::internal::DeathTest* gtest_dt; \
|
if (!::testing::internal::DeathTest::Create( \
|
||||||
if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \
|
#statement, \
|
||||||
__FILE__, __LINE__, >est_dt)) { \
|
::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \
|
||||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
__FILE__, __LINE__, >est_dt)) { \
|
||||||
} \
|
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||||
if (gtest_dt != NULL) { \
|
} \
|
||||||
::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
|
if (gtest_dt != nullptr) { \
|
||||||
gtest_dt_ptr(gtest_dt); \
|
std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \
|
||||||
switch (gtest_dt->AssumeRole()) { \
|
switch (gtest_dt->AssumeRole()) { \
|
||||||
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
||||||
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
||||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||||
} \
|
} \
|
||||||
break; \
|
break; \
|
||||||
case ::testing::internal::DeathTest::EXECUTE_TEST: { \
|
case ::testing::internal::DeathTest::EXECUTE_TEST: { \
|
||||||
::testing::internal::DeathTest::ReturnSentinel \
|
::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \
|
||||||
gtest_sentinel(gtest_dt); \
|
gtest_dt); \
|
||||||
GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
|
GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
|
||||||
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
|
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
default: \
|
default: \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} else \
|
} else \
|
||||||
GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
|
GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \
|
||||||
fail(::testing::internal::DeathTest::LastMessage())
|
: fail(::testing::internal::DeathTest::LastMessage())
|
||||||
// The symbol "fail" here expands to something into which a message
|
// The symbol "fail" here expands to something into which a message
|
||||||
// can be streamed.
|
// can be streamed.
|
||||||
|
|
||||||
// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
|
// 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
|
// NDEBUG mode. In this case we need the statements to be executed and the macro
|
||||||
// ignored, and the macro must accept a streamed message even though the message
|
// must accept a streamed message even though the message is never printed.
|
||||||
// is never printed.
|
// The regex object is not evaluated, but it is used to prevent "unused"
|
||||||
# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
|
// warnings and to avoid an expression that doesn't compile in debug mode.
|
||||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \
|
||||||
if (::testing::internal::AlwaysTrue()) { \
|
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
if (::testing::internal::AlwaysTrue()) { \
|
||||||
} else \
|
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||||
|
} else if (!::testing::internal::AlwaysTrue()) { \
|
||||||
|
::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \
|
||||||
|
} else \
|
||||||
::testing::Message()
|
::testing::Message()
|
||||||
|
|
||||||
// A class representing the parsed contents of the
|
// A class representing the parsed contents of the
|
||||||
|
@ -264,56 +296,9 @@ class InternalRunDeathTestFlag {
|
||||||
// the flag is specified; otherwise returns NULL.
|
// the flag is specified; otherwise returns NULL.
|
||||||
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
|
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
|
#endif // GTEST_HAS_DEATH_TEST
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||||
|
|
|
@ -27,21 +27,24 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
// Author: keith.ray@gmail.com (Keith Ray)
|
|
||||||
//
|
|
||||||
// Google Test filepath utilities
|
// Google Test filepath utilities
|
||||||
//
|
//
|
||||||
// This header file declares classes and functions used internally by
|
// This header file declares classes and functions used internally by
|
||||||
// Google Test. They are subject to change without notice.
|
// Google Test. They are subject to change without notice.
|
||||||
//
|
//
|
||||||
// This file is #included in <gtest/internal/gtest-internal.h>.
|
// This file is #included in gtest/internal/gtest-internal.h.
|
||||||
// Do not include this header file separately!
|
// Do not include this header file separately!
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
// GOOGLETEST_CM0001 DO NOT DELETE
|
||||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
|
||||||
|
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
||||||
|
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
||||||
|
|
||||||
#include "gtest/internal/gtest-string.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 testing {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
@ -107,7 +110,7 @@ class GTEST_API_ FilePath {
|
||||||
const FilePath& base_name,
|
const FilePath& base_name,
|
||||||
const char* extension);
|
const char* extension);
|
||||||
|
|
||||||
// Returns true iff the path is "".
|
// Returns true if and only if the path is "".
|
||||||
bool IsEmpty() const { return pathname_.empty(); }
|
bool IsEmpty() const { return pathname_.empty(); }
|
||||||
|
|
||||||
// If input name has a trailing separator character, removes it and returns
|
// If input name has a trailing separator character, removes it and returns
|
||||||
|
@ -192,7 +195,7 @@ class GTEST_API_ FilePath {
|
||||||
|
|
||||||
void Normalize();
|
void Normalize();
|
||||||
|
|
||||||
// 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
|
// the FilePath. On Windows, for example, both '/' and '\' are valid path
|
||||||
// separators. Returns NULL if no path separator was found.
|
// separators. Returns NULL if no path separator was found.
|
||||||
const char* FindLastPathSeparator() const;
|
const char* FindLastPathSeparator() const;
|
||||||
|
@ -203,4 +206,6 @@ class GTEST_API_ FilePath {
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
|
||||||
|
|
||||||
|
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,33 +26,32 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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.
|
// Type and function utilities for implementing parameterized tests.
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
// GOOGLETEST_CM0001 DO NOT DELETE
|
||||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
|
||||||
|
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
||||||
|
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// 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-internal.h"
|
||||||
#include "gtest/internal/gtest-linked_ptr.h"
|
|
||||||
#include "gtest/internal/gtest-port.h"
|
#include "gtest/internal/gtest-port.h"
|
||||||
#include "gtest/gtest-printers.h"
|
#include "gtest/gtest-printers.h"
|
||||||
|
#include "gtest/gtest-test-part.h"
|
||||||
#if GTEST_HAS_PARAM_TEST
|
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
|
||||||
// Input to a parameterized test name generator, describing a test parameter.
|
// Input to a parameterized test name generator, describing a test parameter.
|
||||||
// Consists of the parameter value and the integer parameter index.
|
// Consists of the parameter value and the integer parameter index.
|
||||||
template <class ParamType>
|
template <class ParamType>
|
||||||
|
@ -76,13 +75,14 @@ struct PrintToStringParamName {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
//
|
// Utility Functions
|
||||||
|
|
||||||
// Outputs a message explaining invalid registration of different
|
// 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
|
// TEST_P macro is used to define two tests with the same name
|
||||||
// but in different namespaces.
|
// but in different namespaces.
|
||||||
GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
|
GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name,
|
||||||
CodeLocation code_location);
|
CodeLocation code_location);
|
||||||
|
|
||||||
template <typename> class ParamGeneratorInterface;
|
template <typename> class ParamGeneratorInterface;
|
||||||
template <typename> class ParamGenerator;
|
template <typename> class ParamGenerator;
|
||||||
|
@ -157,7 +157,7 @@ class ParamIterator {
|
||||||
private:
|
private:
|
||||||
friend class ParamGenerator<T>;
|
friend class ParamGenerator<T>;
|
||||||
explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
|
explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
|
||||||
scoped_ptr<ParamIteratorInterface<T> > impl_;
|
std::unique_ptr<ParamIteratorInterface<T> > impl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ParamGeneratorInterface<T> is the binary interface to access generators
|
// ParamGeneratorInterface<T> is the binary interface to access generators
|
||||||
|
@ -196,7 +196,7 @@ class ParamGenerator {
|
||||||
iterator end() const { return iterator(impl_->End()); }
|
iterator end() const { return iterator(impl_->End()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
linked_ptr<const ParamGeneratorInterface<T> > impl_;
|
std::shared_ptr<const ParamGeneratorInterface<T> > impl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generates values from a range of two comparable values. Can be used to
|
// Generates values from a range of two comparable values. Can be used to
|
||||||
|
@ -209,12 +209,12 @@ class RangeGenerator : public ParamGeneratorInterface<T> {
|
||||||
RangeGenerator(T begin, T end, IncrementT step)
|
RangeGenerator(T begin, T end, IncrementT step)
|
||||||
: begin_(begin), end_(end),
|
: begin_(begin), end_(end),
|
||||||
step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
|
step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
|
||||||
virtual ~RangeGenerator() {}
|
~RangeGenerator() override {}
|
||||||
|
|
||||||
virtual ParamIteratorInterface<T>* Begin() const {
|
ParamIteratorInterface<T>* Begin() const override {
|
||||||
return new Iterator(this, begin_, 0, step_);
|
return new Iterator(this, begin_, 0, step_);
|
||||||
}
|
}
|
||||||
virtual ParamIteratorInterface<T>* End() const {
|
ParamIteratorInterface<T>* End() const override {
|
||||||
return new Iterator(this, end_, end_index_, step_);
|
return new Iterator(this, end_, end_index_, step_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,20 +224,20 @@ class RangeGenerator : public ParamGeneratorInterface<T> {
|
||||||
Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
|
Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
|
||||||
IncrementT step)
|
IncrementT step)
|
||||||
: base_(base), value_(value), index_(index), step_(step) {}
|
: base_(base), value_(value), index_(index), step_(step) {}
|
||||||
virtual ~Iterator() {}
|
~Iterator() override {}
|
||||||
|
|
||||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
const ParamGeneratorInterface<T>* BaseGenerator() const override {
|
||||||
return base_;
|
return base_;
|
||||||
}
|
}
|
||||||
virtual void Advance() {
|
void Advance() override {
|
||||||
value_ = static_cast<T>(value_ + step_);
|
value_ = static_cast<T>(value_ + step_);
|
||||||
index_++;
|
index_++;
|
||||||
}
|
}
|
||||||
virtual ParamIteratorInterface<T>* Clone() const {
|
ParamIteratorInterface<T>* Clone() const override {
|
||||||
return new Iterator(*this);
|
return new Iterator(*this);
|
||||||
}
|
}
|
||||||
virtual const T* Current() const { return &value_; }
|
const T* Current() const override { return &value_; }
|
||||||
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
bool Equals(const ParamIteratorInterface<T>& other) const override {
|
||||||
// Having the same base generator guarantees that the other
|
// Having the same base generator guarantees that the other
|
||||||
// iterator is of the same type and we can downcast.
|
// iterator is of the same type and we can downcast.
|
||||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||||
|
@ -294,12 +294,12 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
|
||||||
template <typename ForwardIterator>
|
template <typename ForwardIterator>
|
||||||
ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
|
ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
|
||||||
: container_(begin, end) {}
|
: container_(begin, end) {}
|
||||||
virtual ~ValuesInIteratorRangeGenerator() {}
|
~ValuesInIteratorRangeGenerator() override {}
|
||||||
|
|
||||||
virtual ParamIteratorInterface<T>* Begin() const {
|
ParamIteratorInterface<T>* Begin() const override {
|
||||||
return new Iterator(this, container_.begin());
|
return new Iterator(this, container_.begin());
|
||||||
}
|
}
|
||||||
virtual ParamIteratorInterface<T>* End() const {
|
ParamIteratorInterface<T>* End() const override {
|
||||||
return new Iterator(this, container_.end());
|
return new Iterator(this, container_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,16 +311,16 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
|
||||||
Iterator(const ParamGeneratorInterface<T>* base,
|
Iterator(const ParamGeneratorInterface<T>* base,
|
||||||
typename ContainerType::const_iterator iterator)
|
typename ContainerType::const_iterator iterator)
|
||||||
: base_(base), iterator_(iterator) {}
|
: base_(base), iterator_(iterator) {}
|
||||||
virtual ~Iterator() {}
|
~Iterator() override {}
|
||||||
|
|
||||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
const ParamGeneratorInterface<T>* BaseGenerator() const override {
|
||||||
return base_;
|
return base_;
|
||||||
}
|
}
|
||||||
virtual void Advance() {
|
void Advance() override {
|
||||||
++iterator_;
|
++iterator_;
|
||||||
value_.reset();
|
value_.reset();
|
||||||
}
|
}
|
||||||
virtual ParamIteratorInterface<T>* Clone() const {
|
ParamIteratorInterface<T>* Clone() const override {
|
||||||
return new Iterator(*this);
|
return new Iterator(*this);
|
||||||
}
|
}
|
||||||
// We need to use cached value referenced by iterator_ because *iterator_
|
// We need to use cached value referenced by iterator_ because *iterator_
|
||||||
|
@ -330,12 +330,11 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
|
||||||
// can advance iterator_ beyond the end of the range, and we cannot
|
// can advance iterator_ beyond the end of the range, and we cannot
|
||||||
// detect that fact. The client code, on the other hand, is
|
// detect that fact. The client code, on the other hand, is
|
||||||
// responsible for not calling Current() on an out-of-range iterator.
|
// responsible for not calling Current() on an out-of-range iterator.
|
||||||
virtual const T* Current() const {
|
const T* Current() const override {
|
||||||
if (value_.get() == NULL)
|
if (value_.get() == nullptr) value_.reset(new T(*iterator_));
|
||||||
value_.reset(new T(*iterator_));
|
|
||||||
return value_.get();
|
return value_.get();
|
||||||
}
|
}
|
||||||
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
bool Equals(const ParamIteratorInterface<T>& other) const override {
|
||||||
// Having the same base generator guarantees that the other
|
// Having the same base generator guarantees that the other
|
||||||
// iterator is of the same type and we can downcast.
|
// iterator is of the same type and we can downcast.
|
||||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||||
|
@ -358,9 +357,9 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
|
||||||
// A cached value of *iterator_. We keep it here to allow access by
|
// A cached value of *iterator_. We keep it here to allow access by
|
||||||
// pointer in the wrapping iterator's operator->().
|
// pointer in the wrapping iterator's operator->().
|
||||||
// value_ needs to be mutable to be accessed in Current().
|
// 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.
|
// which is bound by the lifespan of the iterator itself.
|
||||||
mutable scoped_ptr<const T> value_;
|
mutable std::unique_ptr<const T> value_;
|
||||||
}; // class ValuesInIteratorRangeGenerator::Iterator
|
}; // class ValuesInIteratorRangeGenerator::Iterator
|
||||||
|
|
||||||
// No implementation - assignment is unsupported.
|
// No implementation - assignment is unsupported.
|
||||||
|
@ -380,25 +379,12 @@ std::string DefaultParamName(const TestParamInfo<ParamType>& info) {
|
||||||
return name_stream.GetString();
|
return name_stream.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
template <typename T = int>
|
||||||
//
|
void TestNotEmpty() {
|
||||||
// Parameterized test name overload helpers, which help the
|
static_assert(sizeof(T) == 0, "Empty arguments are not allowed.");
|
||||||
// INSTANTIATE_TEST_CASE_P macro choose between the default parameterized
|
|
||||||
// test name generator and user param name generator.
|
|
||||||
template <class ParamType, class ParamNameGenFunctor>
|
|
||||||
ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) {
|
|
||||||
return func;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ParamType>
|
|
||||||
struct ParamNameGenFunc {
|
|
||||||
typedef std::string Type(const TestParamInfo<ParamType>&);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class ParamType>
|
|
||||||
typename ParamNameGenFunc<ParamType>::Type *GetParamNameGen() {
|
|
||||||
return DefaultParamName;
|
|
||||||
}
|
}
|
||||||
|
template <typename T = int>
|
||||||
|
void TestNotEmpty(const T&) {}
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
//
|
//
|
||||||
|
@ -410,7 +396,7 @@ class ParameterizedTestFactory : public TestFactoryBase {
|
||||||
typedef typename TestClass::ParamType ParamType;
|
typedef typename TestClass::ParamType ParamType;
|
||||||
explicit ParameterizedTestFactory(ParamType parameter) :
|
explicit ParameterizedTestFactory(ParamType parameter) :
|
||||||
parameter_(parameter) {}
|
parameter_(parameter) {}
|
||||||
virtual Test* CreateTest() {
|
Test* CreateTest() override {
|
||||||
TestClass::SetParam(¶meter_);
|
TestClass::SetParam(¶meter_);
|
||||||
return new TestClass();
|
return new TestClass();
|
||||||
}
|
}
|
||||||
|
@ -438,19 +424,19 @@ class TestMetaFactoryBase {
|
||||||
// TestMetaFactory creates test factories for passing into
|
// TestMetaFactory creates test factories for passing into
|
||||||
// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
|
// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
|
||||||
// ownership of test factory pointer, same factory object cannot be passed
|
// 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
|
// it for each Test/Parameter value combination. Thus it needs meta factory
|
||||||
// creator class.
|
// creator class.
|
||||||
template <class TestCase>
|
template <class TestSuite>
|
||||||
class TestMetaFactory
|
class TestMetaFactory
|
||||||
: public TestMetaFactoryBase<typename TestCase::ParamType> {
|
: public TestMetaFactoryBase<typename TestSuite::ParamType> {
|
||||||
public:
|
public:
|
||||||
typedef typename TestCase::ParamType ParamType;
|
using ParamType = typename TestSuite::ParamType;
|
||||||
|
|
||||||
TestMetaFactory() {}
|
TestMetaFactory() {}
|
||||||
|
|
||||||
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
|
TestFactoryBase* CreateTestFactory(ParamType parameter) override {
|
||||||
return new ParameterizedTestFactory<TestCase>(parameter);
|
return new ParameterizedTestFactory<TestSuite>(parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -459,113 +445,128 @@ class TestMetaFactory
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
//
|
//
|
||||||
// ParameterizedTestCaseInfoBase is a generic interface
|
// ParameterizedTestSuiteInfoBase is a generic interface
|
||||||
// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
|
// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase
|
||||||
// accumulates test information provided by TEST_P macro invocations
|
// 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
|
// and uses that information to register all resulting test instances
|
||||||
// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
|
// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds
|
||||||
// a collection of pointers to the ParameterizedTestCaseInfo objects
|
// a collection of pointers to the ParameterizedTestSuiteInfo objects
|
||||||
// and calls RegisterTests() on each of them when asked.
|
// and calls RegisterTests() on each of them when asked.
|
||||||
class ParameterizedTestCaseInfoBase {
|
class ParameterizedTestSuiteInfoBase {
|
||||||
public:
|
public:
|
||||||
virtual ~ParameterizedTestCaseInfoBase() {}
|
virtual ~ParameterizedTestSuiteInfoBase() {}
|
||||||
|
|
||||||
// Base part of test case name for display purposes.
|
// Base part of test suite name for display purposes.
|
||||||
virtual const string& GetTestCaseName() const = 0;
|
virtual const std::string& GetTestSuiteName() const = 0;
|
||||||
// Test case id to verify identity.
|
// Test suite id to verify identity.
|
||||||
virtual TypeId GetTestCaseTypeId() const = 0;
|
virtual TypeId GetTestSuiteTypeId() const = 0;
|
||||||
// UnitTest class invokes this method to register tests in this
|
// UnitTest class invokes this method to register tests in this
|
||||||
// test case right before running them in RUN_ALL_TESTS macro.
|
// test suite right before running them in RUN_ALL_TESTS macro.
|
||||||
// This method should not be called more then once on any single
|
// This method should not be called more than once on any single
|
||||||
// instance of a ParameterizedTestCaseInfoBase derived class.
|
// instance of a ParameterizedTestSuiteInfoBase derived class.
|
||||||
virtual void RegisterTests() = 0;
|
virtual void RegisterTests() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ParameterizedTestCaseInfoBase() {}
|
ParameterizedTestSuiteInfoBase() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase);
|
||||||
};
|
};
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
//
|
//
|
||||||
// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
|
// Report a the name of a test_suit as safe to ignore
|
||||||
// macro invocations for a particular test case and generators
|
// as the side effect of construction of this type.
|
||||||
// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
|
struct GTEST_API_ MarkAsIgnored {
|
||||||
// test case. It registers tests with all values generated by all
|
explicit MarkAsIgnored(const char* test_suite);
|
||||||
|
};
|
||||||
|
|
||||||
|
GTEST_API_ void InsertSyntheticTestCase(const std::string& name,
|
||||||
|
CodeLocation location, bool has_test_p);
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
|
//
|
||||||
|
// 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.
|
// generators when asked.
|
||||||
template <class TestCase>
|
template <class TestSuite>
|
||||||
class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
|
class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase {
|
||||||
public:
|
public:
|
||||||
// ParamType and GeneratorCreationFunc are private types but are required
|
// ParamType and GeneratorCreationFunc are private types but are required
|
||||||
// for declarations of public methods AddTestPattern() and
|
// for declarations of public methods AddTestPattern() and
|
||||||
// AddTestCaseInstantiation().
|
// AddTestSuiteInstantiation().
|
||||||
typedef typename TestCase::ParamType ParamType;
|
using ParamType = typename TestSuite::ParamType;
|
||||||
// A function that returns an instance of appropriate generator type.
|
// A function that returns an instance of appropriate generator type.
|
||||||
typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
|
typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
|
||||||
typedef typename ParamNameGenFunc<ParamType>::Type ParamNameGeneratorFunc;
|
using ParamNameGeneratorFunc = std::string(const TestParamInfo<ParamType>&);
|
||||||
|
|
||||||
explicit ParameterizedTestCaseInfo(
|
explicit ParameterizedTestSuiteInfo(const char* name,
|
||||||
const char* name, CodeLocation code_location)
|
CodeLocation code_location)
|
||||||
: test_case_name_(name), code_location_(code_location) {}
|
: test_suite_name_(name), code_location_(code_location) {}
|
||||||
|
|
||||||
// Test case base name for display purposes.
|
// Test suite base name for display purposes.
|
||||||
virtual const string& GetTestCaseName() const { return test_case_name_; }
|
const std::string& GetTestSuiteName() const override {
|
||||||
// Test case id to verify identity.
|
return test_suite_name_;
|
||||||
virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
|
}
|
||||||
|
// Test suite id to verify identity.
|
||||||
|
TypeId GetTestSuiteTypeId() const override { return GetTypeId<TestSuite>(); }
|
||||||
// TEST_P macro uses AddTestPattern() to record information
|
// TEST_P macro uses AddTestPattern() to record information
|
||||||
// about a single test in a LocalTestInfo structure.
|
// 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
|
// prefix). test_base_name is the name of an individual test without
|
||||||
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
||||||
// test case base name and DoBar is test base name.
|
// test suite base name and DoBar is test base name.
|
||||||
void AddTestPattern(const char* test_case_name,
|
void AddTestPattern(const char* test_suite_name, const char* test_base_name,
|
||||||
const char* test_base_name,
|
TestMetaFactoryBase<ParamType>* meta_factory,
|
||||||
TestMetaFactoryBase<ParamType>* meta_factory) {
|
CodeLocation code_location) {
|
||||||
tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
|
tests_.push_back(std::shared_ptr<TestInfo>(new TestInfo(
|
||||||
test_base_name,
|
test_suite_name, test_base_name, meta_factory, code_location)));
|
||||||
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.
|
// about a generator.
|
||||||
int AddTestCaseInstantiation(const string& instantiation_name,
|
int AddTestSuiteInstantiation(const std::string& instantiation_name,
|
||||||
GeneratorCreationFunc* func,
|
GeneratorCreationFunc* func,
|
||||||
ParamNameGeneratorFunc* name_func,
|
ParamNameGeneratorFunc* name_func,
|
||||||
const char* file,
|
const char* file, int line) {
|
||||||
int line) {
|
|
||||||
instantiations_.push_back(
|
instantiations_.push_back(
|
||||||
InstantiationInfo(instantiation_name, func, name_func, file, line));
|
InstantiationInfo(instantiation_name, func, name_func, file, line));
|
||||||
return 0; // Return value used only to run this method in namespace scope.
|
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
|
// UnitTest class invokes this method to register tests in this test suite
|
||||||
// test cases right before running tests in RUN_ALL_TESTS macro.
|
// right before running tests in RUN_ALL_TESTS macro.
|
||||||
// This method should not be called more then once on any single
|
// This method should not be called more than once on any single
|
||||||
// instance of a ParameterizedTestCaseInfoBase derived class.
|
// instance of a ParameterizedTestSuiteInfoBase derived class.
|
||||||
// UnitTest has a guard to prevent from calling this method more then once.
|
// UnitTest has a guard to prevent from calling this method more than once.
|
||||||
virtual void RegisterTests() {
|
void RegisterTests() override {
|
||||||
|
bool generated_instantiations = false;
|
||||||
|
|
||||||
for (typename TestInfoContainer::iterator test_it = tests_.begin();
|
for (typename TestInfoContainer::iterator test_it = tests_.begin();
|
||||||
test_it != tests_.end(); ++test_it) {
|
test_it != tests_.end(); ++test_it) {
|
||||||
linked_ptr<TestInfo> test_info = *test_it;
|
std::shared_ptr<TestInfo> test_info = *test_it;
|
||||||
for (typename InstantiationContainer::iterator gen_it =
|
for (typename InstantiationContainer::iterator gen_it =
|
||||||
instantiations_.begin(); gen_it != instantiations_.end();
|
instantiations_.begin(); gen_it != instantiations_.end();
|
||||||
++gen_it) {
|
++gen_it) {
|
||||||
const string& instantiation_name = gen_it->name;
|
const std::string& instantiation_name = gen_it->name;
|
||||||
ParamGenerator<ParamType> generator((*gen_it->generator)());
|
ParamGenerator<ParamType> generator((*gen_it->generator)());
|
||||||
ParamNameGeneratorFunc* name_func = gen_it->name_func;
|
ParamNameGeneratorFunc* name_func = gen_it->name_func;
|
||||||
const char* file = gen_it->file;
|
const char* file = gen_it->file;
|
||||||
int line = gen_it->line;
|
int line = gen_it->line;
|
||||||
|
|
||||||
string test_case_name;
|
std::string test_suite_name;
|
||||||
if ( !instantiation_name.empty() )
|
if ( !instantiation_name.empty() )
|
||||||
test_case_name = instantiation_name + "/";
|
test_suite_name = instantiation_name + "/";
|
||||||
test_case_name += test_info->test_case_base_name;
|
test_suite_name += test_info->test_suite_base_name;
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
std::set<std::string> test_param_names;
|
std::set<std::string> test_param_names;
|
||||||
for (typename ParamGenerator<ParamType>::iterator param_it =
|
for (typename ParamGenerator<ParamType>::iterator param_it =
|
||||||
generator.begin();
|
generator.begin();
|
||||||
param_it != generator.end(); ++param_it, ++i) {
|
param_it != generator.end(); ++param_it, ++i) {
|
||||||
|
generated_instantiations = true;
|
||||||
|
|
||||||
Message test_name_stream;
|
Message test_name_stream;
|
||||||
|
|
||||||
std::string param_name = name_func(
|
std::string param_name = name_func(
|
||||||
|
@ -582,39 +583,48 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
|
||||||
|
|
||||||
test_param_names.insert(param_name);
|
test_param_names.insert(param_name);
|
||||||
|
|
||||||
test_name_stream << test_info->test_base_name << "/" << param_name;
|
if (!test_info->test_base_name.empty()) {
|
||||||
|
test_name_stream << test_info->test_base_name << "/";
|
||||||
|
}
|
||||||
|
test_name_stream << param_name;
|
||||||
MakeAndRegisterTestInfo(
|
MakeAndRegisterTestInfo(
|
||||||
test_case_name.c_str(),
|
test_suite_name.c_str(), test_name_stream.GetString().c_str(),
|
||||||
test_name_stream.GetString().c_str(),
|
nullptr, // No type parameter.
|
||||||
NULL, // No type parameter.
|
PrintToString(*param_it).c_str(), test_info->code_location,
|
||||||
PrintToString(*param_it).c_str(),
|
GetTestSuiteTypeId(),
|
||||||
code_location_,
|
SuiteApiResolver<TestSuite>::GetSetUpCaseOrSuite(file, line),
|
||||||
GetTestCaseTypeId(),
|
SuiteApiResolver<TestSuite>::GetTearDownCaseOrSuite(file, line),
|
||||||
TestCase::SetUpTestCase,
|
|
||||||
TestCase::TearDownTestCase,
|
|
||||||
test_info->test_meta_factory->CreateTestFactory(*param_it));
|
test_info->test_meta_factory->CreateTestFactory(*param_it));
|
||||||
} // for param_it
|
} // for param_it
|
||||||
} // for gen_it
|
} // for gen_it
|
||||||
} // for test_it
|
} // for test_it
|
||||||
} // RegisterTests
|
|
||||||
|
if (!generated_instantiations) {
|
||||||
|
// There are no generaotrs, or they all generate nothing ...
|
||||||
|
InsertSyntheticTestCase(GetTestSuiteName(), code_location_,
|
||||||
|
!tests_.empty());
|
||||||
|
}
|
||||||
|
} // RegisterTests
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// LocalTestInfo structure keeps information about a single test registered
|
// LocalTestInfo structure keeps information about a single test registered
|
||||||
// with TEST_P macro.
|
// with TEST_P macro.
|
||||||
struct TestInfo {
|
struct TestInfo {
|
||||||
TestInfo(const char* a_test_case_base_name,
|
TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name,
|
||||||
const char* a_test_base_name,
|
TestMetaFactoryBase<ParamType>* a_test_meta_factory,
|
||||||
TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
|
CodeLocation a_code_location)
|
||||||
test_case_base_name(a_test_case_base_name),
|
: test_suite_base_name(a_test_suite_base_name),
|
||||||
test_base_name(a_test_base_name),
|
test_base_name(a_test_base_name),
|
||||||
test_meta_factory(a_test_meta_factory) {}
|
test_meta_factory(a_test_meta_factory),
|
||||||
|
code_location(a_code_location) {}
|
||||||
|
|
||||||
const string test_case_base_name;
|
const std::string test_suite_base_name;
|
||||||
const string test_base_name;
|
const std::string test_base_name;
|
||||||
const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
|
const std::unique_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
|
||||||
|
const CodeLocation code_location;
|
||||||
};
|
};
|
||||||
typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
|
using TestInfoContainer = ::std::vector<std::shared_ptr<TestInfo> >;
|
||||||
// Records data received from INSTANTIATE_TEST_CASE_P macros:
|
// Records data received from INSTANTIATE_TEST_SUITE_P macros:
|
||||||
// <Instantiation name, Sequence generator creation function,
|
// <Instantiation name, Sequence generator creation function,
|
||||||
// Name generator function, Source file, Source line>
|
// Name generator function, Source file, Source line>
|
||||||
struct InstantiationInfo {
|
struct InstantiationInfo {
|
||||||
|
@ -651,81 +661,287 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string test_case_name_;
|
const std::string test_suite_name_;
|
||||||
CodeLocation code_location_;
|
CodeLocation code_location_;
|
||||||
TestInfoContainer tests_;
|
TestInfoContainer tests_;
|
||||||
InstantiationContainer instantiations_;
|
InstantiationContainer instantiations_;
|
||||||
|
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo);
|
||||||
}; // class ParameterizedTestCaseInfo
|
}; // class ParameterizedTestSuiteInfo
|
||||||
|
|
||||||
|
// Legacy API is deprecated but still available
|
||||||
|
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
|
template <class TestCase>
|
||||||
|
using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo<TestCase>;
|
||||||
|
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
|
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
//
|
//
|
||||||
// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
|
// ParameterizedTestSuiteRegistry contains a map of
|
||||||
// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
|
// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P
|
||||||
// macros use it to locate their corresponding ParameterizedTestCaseInfo
|
// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding
|
||||||
// descriptors.
|
// ParameterizedTestSuiteInfo descriptors.
|
||||||
class ParameterizedTestCaseRegistry {
|
class ParameterizedTestSuiteRegistry {
|
||||||
public:
|
public:
|
||||||
ParameterizedTestCaseRegistry() {}
|
ParameterizedTestSuiteRegistry() {}
|
||||||
~ParameterizedTestCaseRegistry() {
|
~ParameterizedTestSuiteRegistry() {
|
||||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
for (auto& test_suite_info : test_suite_infos_) {
|
||||||
it != test_case_infos_.end(); ++it) {
|
delete test_suite_info;
|
||||||
delete *it;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Looks up or creates and returns a structure containing information about
|
// Looks up or creates and returns a structure containing information about
|
||||||
// tests and instantiations of a particular test case.
|
// tests and instantiations of a particular test suite.
|
||||||
template <class TestCase>
|
template <class TestSuite>
|
||||||
ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
|
ParameterizedTestSuiteInfo<TestSuite>* GetTestSuitePatternHolder(
|
||||||
const char* test_case_name,
|
const char* test_suite_name, CodeLocation code_location) {
|
||||||
CodeLocation code_location) {
|
ParameterizedTestSuiteInfo<TestSuite>* typed_test_info = nullptr;
|
||||||
ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
|
for (auto& test_suite_info : test_suite_infos_) {
|
||||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
if (test_suite_info->GetTestSuiteName() == test_suite_name) {
|
||||||
it != test_case_infos_.end(); ++it) {
|
if (test_suite_info->GetTestSuiteTypeId() != GetTypeId<TestSuite>()) {
|
||||||
if ((*it)->GetTestCaseName() == test_case_name) {
|
|
||||||
if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
|
|
||||||
// Complain about incorrect usage of Google Test facilities
|
// Complain about incorrect usage of Google Test facilities
|
||||||
// and terminate the program since we cannot guaranty correct
|
// and terminate the program since we cannot guaranty correct
|
||||||
// test case setup and tear-down in this case.
|
// test suite setup and tear-down in this case.
|
||||||
ReportInvalidTestCaseType(test_case_name, code_location);
|
ReportInvalidTestSuiteType(test_suite_name, code_location);
|
||||||
posix::Abort();
|
posix::Abort();
|
||||||
} else {
|
} else {
|
||||||
// At this point we are sure that the object we found is of the same
|
// 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
|
// type we are looking for, so we downcast it to that type
|
||||||
// without further checks.
|
// without further checks.
|
||||||
typed_test_info = CheckedDowncastToActualType<
|
typed_test_info = CheckedDowncastToActualType<
|
||||||
ParameterizedTestCaseInfo<TestCase> >(*it);
|
ParameterizedTestSuiteInfo<TestSuite> >(test_suite_info);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typed_test_info == NULL) {
|
if (typed_test_info == nullptr) {
|
||||||
typed_test_info = new ParameterizedTestCaseInfo<TestCase>(
|
typed_test_info = new ParameterizedTestSuiteInfo<TestSuite>(
|
||||||
test_case_name, code_location);
|
test_suite_name, code_location);
|
||||||
test_case_infos_.push_back(typed_test_info);
|
test_suite_infos_.push_back(typed_test_info);
|
||||||
}
|
}
|
||||||
return typed_test_info;
|
return typed_test_info;
|
||||||
}
|
}
|
||||||
void RegisterTests() {
|
void RegisterTests() {
|
||||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
for (auto& test_suite_info : test_suite_infos_) {
|
||||||
it != test_case_infos_.end(); ++it) {
|
test_suite_info->RegisterTests();
|
||||||
(*it)->RegisterTests();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Legacy API is deprecated but still available
|
||||||
|
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
|
template <class TestCase>
|
||||||
|
ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
|
||||||
|
const char* test_case_name, CodeLocation code_location) {
|
||||||
|
return GetTestSuitePatternHolder<TestCase>(test_case_name, code_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
|
|
||||||
|
private:
|
||||||
|
using TestSuiteInfoContainer = ::std::vector<ParameterizedTestSuiteInfoBase*>;
|
||||||
|
|
||||||
|
TestSuiteInfoContainer test_suite_infos_;
|
||||||
|
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep track of what type-parameterized test suite are defined and
|
||||||
|
// where as well as which are intatiated. This allows susequently
|
||||||
|
// identifying suits that are defined but never used.
|
||||||
|
class TypeParameterizedTestSuiteRegistry {
|
||||||
|
public:
|
||||||
|
// Add a suite definition
|
||||||
|
void RegisterTestSuite(const char* test_suite_name,
|
||||||
|
CodeLocation code_location);
|
||||||
|
|
||||||
|
// Add an instantiation of a suit.
|
||||||
|
void RegisterInstantiation(const char* test_suite_name);
|
||||||
|
|
||||||
|
// For each suit repored as defined but not reported as instantiation,
|
||||||
|
// emit a test that reports that fact (configurably, as an error).
|
||||||
|
void CheckForInstantiations();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct TypeParameterizedTestSuiteInfo {
|
||||||
|
explicit TypeParameterizedTestSuiteInfo(CodeLocation c)
|
||||||
|
: code_location(c), instantiated(false) {}
|
||||||
|
|
||||||
|
CodeLocation code_location;
|
||||||
|
bool instantiated;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string, TypeParameterizedTestSuiteInfo> suites_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// Forward declarations of ValuesIn(), which is implemented in
|
||||||
|
// include/gtest/gtest-param-test.h.
|
||||||
|
template <class Container>
|
||||||
|
internal::ParamGenerator<typename Container::value_type> ValuesIn(
|
||||||
|
const Container& container);
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
// Used in the Values() function to provide polymorphic capabilities.
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4100)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
class ValueArray {
|
||||||
|
public:
|
||||||
|
explicit ValueArray(Ts... v) : v_(FlatTupleConstructTag{}, std::move(v)...) {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
operator ParamGenerator<T>() const { // NOLINT
|
||||||
|
return ValuesIn(MakeVector<T>(MakeIndexSequence<sizeof...(Ts)>()));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
|
template <typename T, size_t... I>
|
||||||
|
std::vector<T> MakeVector(IndexSequence<I...>) const {
|
||||||
|
return std::vector<T>{static_cast<T>(v_.template Get<I>())...};
|
||||||
|
}
|
||||||
|
|
||||||
TestCaseInfoContainer test_case_infos_;
|
FlatTuple<Ts...> v_;
|
||||||
|
};
|
||||||
|
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
class CartesianProductGenerator
|
||||||
|
: public ParamGeneratorInterface<::std::tuple<T...>> {
|
||||||
|
public:
|
||||||
|
typedef ::std::tuple<T...> ParamType;
|
||||||
|
|
||||||
|
CartesianProductGenerator(const std::tuple<ParamGenerator<T>...>& g)
|
||||||
|
: generators_(g) {}
|
||||||
|
~CartesianProductGenerator() override {}
|
||||||
|
|
||||||
|
ParamIteratorInterface<ParamType>* Begin() const override {
|
||||||
|
return new Iterator(this, generators_, false);
|
||||||
|
}
|
||||||
|
ParamIteratorInterface<ParamType>* End() const override {
|
||||||
|
return new Iterator(this, generators_, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <class I>
|
||||||
|
class IteratorImpl;
|
||||||
|
template <size_t... I>
|
||||||
|
class IteratorImpl<IndexSequence<I...>>
|
||||||
|
: public ParamIteratorInterface<ParamType> {
|
||||||
|
public:
|
||||||
|
IteratorImpl(const ParamGeneratorInterface<ParamType>* base,
|
||||||
|
const std::tuple<ParamGenerator<T>...>& generators, bool is_end)
|
||||||
|
: base_(base),
|
||||||
|
begin_(std::get<I>(generators).begin()...),
|
||||||
|
end_(std::get<I>(generators).end()...),
|
||||||
|
current_(is_end ? end_ : begin_) {
|
||||||
|
ComputeCurrentValue();
|
||||||
|
}
|
||||||
|
~IteratorImpl() override {}
|
||||||
|
|
||||||
|
const ParamGeneratorInterface<ParamType>* 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<sizeof...(T) - 1>(current_);
|
||||||
|
// if that reaches end, propagate that up.
|
||||||
|
AdvanceIfEnd<sizeof...(T) - 1>();
|
||||||
|
ComputeCurrentValue();
|
||||||
|
}
|
||||||
|
ParamIteratorInterface<ParamType>* Clone() const override {
|
||||||
|
return new IteratorImpl(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ParamType* Current() const override { return current_value_.get(); }
|
||||||
|
|
||||||
|
bool Equals(const ParamIteratorInterface<ParamType>& 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<const IteratorImpl>(&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<I>(current_) ==
|
||||||
|
std::get<I>(typed_other->current_))...};
|
||||||
|
(void)dummy;
|
||||||
|
return same;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <size_t ThisI>
|
||||||
|
void AdvanceIfEnd() {
|
||||||
|
if (std::get<ThisI>(current_) != std::get<ThisI>(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<ThisI>(current_) = std::get<ThisI>(begin_);
|
||||||
|
++std::get<NextI>(current_);
|
||||||
|
AdvanceIfEnd<NextI>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComputeCurrentValue() {
|
||||||
|
if (!AtEnd())
|
||||||
|
current_value_ = std::make_shared<ParamType>(*std::get<I>(current_)...);
|
||||||
|
}
|
||||||
|
bool AtEnd() const {
|
||||||
|
bool at_end = false;
|
||||||
|
bool dummy[] = {
|
||||||
|
(at_end = at_end || std::get<I>(current_) == std::get<I>(end_))...};
|
||||||
|
(void)dummy;
|
||||||
|
return at_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ParamGeneratorInterface<ParamType>* const base_;
|
||||||
|
std::tuple<typename ParamGenerator<T>::iterator...> begin_;
|
||||||
|
std::tuple<typename ParamGenerator<T>::iterator...> end_;
|
||||||
|
std::tuple<typename ParamGenerator<T>::iterator...> current_;
|
||||||
|
std::shared_ptr<ParamType> current_value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Iterator = IteratorImpl<typename MakeIndexSequence<sizeof...(T)>::type>;
|
||||||
|
|
||||||
|
std::tuple<ParamGenerator<T>...> generators_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class... Gen>
|
||||||
|
class CartesianProductHolder {
|
||||||
|
public:
|
||||||
|
CartesianProductHolder(const Gen&... g) : generators_(g...) {}
|
||||||
|
template <typename... T>
|
||||||
|
operator ParamGenerator<::std::tuple<T...>>() const {
|
||||||
|
return ParamGenerator<::std::tuple<T...>>(
|
||||||
|
new CartesianProductGenerator<T...>(generators_));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::tuple<Gen...> generators_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
#endif // GTEST_HAS_PARAM_TEST
|
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
|
||||||
|
|
|
@ -27,25 +27,24 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
// The Google C++ Testing Framework (Google Test)
|
// The Google C++ Testing and Mocking Framework (Google Test)
|
||||||
//
|
//
|
||||||
// This header file defines the GTEST_OS_* macro.
|
// This header file defines the GTEST_OS_* macro.
|
||||||
// It is separate from gtest-port.h so that custom/gtest-port.h can include it.
|
// 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_
|
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
|
||||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
|
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
|
||||||
|
|
||||||
// Determines the platform on which Google Test is compiled.
|
// Determines the platform on which Google Test is compiled.
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
# define GTEST_OS_CYGWIN 1
|
# define GTEST_OS_CYGWIN 1
|
||||||
#elif defined __SYMBIAN32__
|
# elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
# define GTEST_OS_SYMBIAN 1
|
# define GTEST_OS_WINDOWS_MINGW 1
|
||||||
|
# define GTEST_OS_WINDOWS 1
|
||||||
#elif defined _WIN32
|
#elif defined _WIN32
|
||||||
# define GTEST_OS_WINDOWS 1
|
# define GTEST_OS_WINDOWS 1
|
||||||
# ifdef _WIN32_WCE
|
# ifdef _WIN32_WCE
|
||||||
# define GTEST_OS_WINDOWS_MOBILE 1
|
# define GTEST_OS_WINDOWS_MOBILE 1
|
||||||
# elif defined(__MINGW__) || defined(__MINGW32__)
|
|
||||||
# define GTEST_OS_WINDOWS_MINGW 1
|
|
||||||
# elif defined(WINAPI_FAMILY)
|
# elif defined(WINAPI_FAMILY)
|
||||||
# include <winapifamily.h>
|
# include <winapifamily.h>
|
||||||
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||||
|
@ -54,6 +53,9 @@
|
||||||
# define GTEST_OS_WINDOWS_PHONE 1
|
# define GTEST_OS_WINDOWS_PHONE 1
|
||||||
# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||||
# define GTEST_OS_WINDOWS_RT 1
|
# 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
|
# else
|
||||||
// WINAPI_FAMILY defined but no known partition matched.
|
// WINAPI_FAMILY defined but no known partition matched.
|
||||||
// Default to desktop.
|
// Default to desktop.
|
||||||
|
@ -62,13 +64,22 @@
|
||||||
# else
|
# else
|
||||||
# define GTEST_OS_WINDOWS_DESKTOP 1
|
# define GTEST_OS_WINDOWS_DESKTOP 1
|
||||||
# endif // _WIN32_WCE
|
# endif // _WIN32_WCE
|
||||||
|
#elif defined __OS2__
|
||||||
|
# define GTEST_OS_OS2 1
|
||||||
#elif defined __APPLE__
|
#elif defined __APPLE__
|
||||||
# define GTEST_OS_MAC 1
|
# define GTEST_OS_MAC 1
|
||||||
|
# include <TargetConditionals.h>
|
||||||
# if TARGET_OS_IPHONE
|
# if TARGET_OS_IPHONE
|
||||||
# define GTEST_OS_IOS 1
|
# define GTEST_OS_IOS 1
|
||||||
# endif
|
# endif
|
||||||
|
#elif defined __DragonFly__
|
||||||
|
# define GTEST_OS_DRAGONFLY 1
|
||||||
#elif defined __FreeBSD__
|
#elif defined __FreeBSD__
|
||||||
# define GTEST_OS_FREEBSD 1
|
# 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__
|
#elif defined __linux__
|
||||||
# define GTEST_OS_LINUX 1
|
# define GTEST_OS_LINUX 1
|
||||||
# if defined __ANDROID__
|
# if defined __ANDROID__
|
||||||
|
@ -84,10 +95,20 @@
|
||||||
# define GTEST_OS_HPUX 1
|
# define GTEST_OS_HPUX 1
|
||||||
#elif defined __native_client__
|
#elif defined __native_client__
|
||||||
# define GTEST_OS_NACL 1
|
# define GTEST_OS_NACL 1
|
||||||
|
#elif defined __NetBSD__
|
||||||
|
# define GTEST_OS_NETBSD 1
|
||||||
#elif defined __OpenBSD__
|
#elif defined __OpenBSD__
|
||||||
# define GTEST_OS_OPENBSD 1
|
# define GTEST_OS_OPENBSD 1
|
||||||
#elif defined __QNX__
|
#elif defined __QNX__
|
||||||
# define GTEST_OS_QNX 1
|
# define GTEST_OS_QNX 1
|
||||||
|
#elif defined(__HAIKU__)
|
||||||
|
#define GTEST_OS_HAIKU 1
|
||||||
|
#elif defined ESP8266
|
||||||
|
#define GTEST_OS_ESP8266 1
|
||||||
|
#elif defined ESP32
|
||||||
|
#define GTEST_OS_ESP32 1
|
||||||
|
#elif defined(__XTENSA__)
|
||||||
|
#define GTEST_OS_XTENSA 1
|
||||||
#endif // __CYGWIN__
|
#endif // __CYGWIN__
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
|
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -27,19 +27,19 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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 and Mocking Framework (Google Test)
|
||||||
//
|
|
||||||
// The Google C++ Testing Framework (Google Test)
|
|
||||||
//
|
//
|
||||||
// This header file declares the String class and functions used internally by
|
// 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
|
// Google Test. They are subject to change without notice. They should not used
|
||||||
// by code external to Google Test.
|
// by code external to Google Test.
|
||||||
//
|
//
|
||||||
// This header file is #included by <gtest/internal/gtest-internal.h>.
|
// This header file is #included by gtest-internal.h.
|
||||||
// It should not be #included by other files.
|
// It should not be #included by other files.
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
// GOOGLETEST_CM0001 DO NOT DELETE
|
||||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
|
||||||
|
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||||
|
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||||
|
|
||||||
#ifdef __BORLANDC__
|
#ifdef __BORLANDC__
|
||||||
// string.h is not guaranteed to provide strcpy on C++ Builder.
|
// string.h is not guaranteed to provide strcpy on C++ Builder.
|
||||||
|
@ -47,6 +47,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "gtest/internal/gtest-port.h"
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
@ -94,7 +95,8 @@ class GTEST_API_ String {
|
||||||
static const char* Utf16ToAnsi(LPCWSTR utf16_str);
|
static const char* Utf16ToAnsi(LPCWSTR utf16_str);
|
||||||
#endif
|
#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
|
// Unlike strcmp(), this function can handle NULL argument(s). A
|
||||||
// NULL C string is considered different to any non-NULL C string,
|
// NULL C string is considered different to any non-NULL C string,
|
||||||
|
@ -107,16 +109,16 @@ class GTEST_API_ String {
|
||||||
// returned.
|
// returned.
|
||||||
static std::string ShowWideCString(const wchar_t* wide_c_str);
|
static std::string ShowWideCString(const wchar_t* wide_c_str);
|
||||||
|
|
||||||
// Compares two wide C strings. Returns true iff they have the same
|
// Compares two wide C strings. Returns true if and only if they have the
|
||||||
// content.
|
// same content.
|
||||||
//
|
//
|
||||||
// Unlike wcscmp(), this function can handle NULL argument(s). A
|
// Unlike wcscmp(), this function can handle NULL argument(s). A
|
||||||
// NULL C string is considered different to any non-NULL C string,
|
// NULL C string is considered different to any non-NULL C string,
|
||||||
// including the empty string.
|
// including the empty string.
|
||||||
static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
|
static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
|
||||||
|
|
||||||
// Compares two C strings, ignoring case. Returns true iff they
|
// Compares two C strings, ignoring case. Returns true if and only if
|
||||||
// have the same content.
|
// they have the same content.
|
||||||
//
|
//
|
||||||
// Unlike strcasecmp(), this function can handle NULL argument(s).
|
// Unlike strcasecmp(), this function can handle NULL argument(s).
|
||||||
// A NULL C string is considered different to any non-NULL C string,
|
// A NULL C string is considered different to any non-NULL C string,
|
||||||
|
@ -124,8 +126,8 @@ class GTEST_API_ String {
|
||||||
static bool CaseInsensitiveCStringEquals(const char* lhs,
|
static bool CaseInsensitiveCStringEquals(const char* lhs,
|
||||||
const char* rhs);
|
const char* rhs);
|
||||||
|
|
||||||
// Compares two wide C strings, ignoring case. Returns true iff they
|
// Compares two wide C strings, ignoring case. Returns true if and only if
|
||||||
// have the same content.
|
// they have the same content.
|
||||||
//
|
//
|
||||||
// Unlike wcscasecmp(), this function can handle NULL argument(s).
|
// Unlike wcscasecmp(), this function can handle NULL argument(s).
|
||||||
// A NULL C string is considered different to any non-NULL wide C string,
|
// A NULL C string is considered different to any non-NULL wide C string,
|
||||||
|
@ -139,17 +141,23 @@ class GTEST_API_ String {
|
||||||
static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
|
static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
|
||||||
const wchar_t* rhs);
|
const wchar_t* rhs);
|
||||||
|
|
||||||
// Returns true iff the given string ends with the given suffix, ignoring
|
// Returns true if and only if the given string ends with the given suffix,
|
||||||
// case. Any string is considered to end with an empty suffix.
|
// ignoring case. Any string is considered to end with an empty suffix.
|
||||||
static bool EndsWithCaseInsensitive(
|
static bool EndsWithCaseInsensitive(
|
||||||
const std::string& str, const std::string& suffix);
|
const std::string& str, const std::string& suffix);
|
||||||
|
|
||||||
// Formats an int value as "%02d".
|
// Formats an int value as "%02d".
|
||||||
static std::string FormatIntWidth2(int value); // "%02d" for width == 2
|
static std::string FormatIntWidth2(int value); // "%02d" for width == 2
|
||||||
|
|
||||||
|
// Formats an int value to given width with leading zeros.
|
||||||
|
static std::string FormatIntWidthN(int value, int width);
|
||||||
|
|
||||||
// Formats an int value as "%X".
|
// Formats an int value as "%X".
|
||||||
static std::string FormatHexInt(int value);
|
static std::string FormatHexInt(int value);
|
||||||
|
|
||||||
|
// Formats an int value as "%X".
|
||||||
|
static std::string FormatHexUInt32(uint32_t value);
|
||||||
|
|
||||||
// Formats a byte as "%02X".
|
// Formats a byte as "%02X".
|
||||||
static std::string FormatByte(unsigned char value);
|
static std::string FormatByte(unsigned char value);
|
||||||
|
|
||||||
|
@ -164,4 +172,4 @@ GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,16 +26,15 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
// Author: vladl@google.com (Vlad Losev)
|
|
||||||
|
|
||||||
// This provides interface PrimeTable that determines whether a number is a
|
// This provides interface PrimeTable that determines whether a number is a
|
||||||
// prime and determines a next prime number. This interface is used
|
// prime and determines a next prime number. This interface is used
|
||||||
// in Google Test samples demonstrating use of parameterized tests.
|
// in Google Test samples demonstrating use of parameterized tests.
|
||||||
|
|
||||||
#ifndef GTEST_SAMPLES_PRIME_TABLES_H_
|
#ifndef GOOGLETEST_SAMPLES_PRIME_TABLES_H_
|
||||||
#define GTEST_SAMPLES_PRIME_TABLES_H_
|
#define GOOGLETEST_SAMPLES_PRIME_TABLES_H_
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -44,7 +43,7 @@ class PrimeTable {
|
||||||
public:
|
public:
|
||||||
virtual ~PrimeTable() {}
|
virtual ~PrimeTable() {}
|
||||||
|
|
||||||
// Returns true iff n is a prime number.
|
// Returns true if and only if n is a prime number.
|
||||||
virtual bool IsPrime(int n) const = 0;
|
virtual bool IsPrime(int n) const = 0;
|
||||||
|
|
||||||
// Returns the smallest prime number greater than p; or returns -1
|
// Returns the smallest prime number greater than p; or returns -1
|
||||||
|
@ -55,7 +54,7 @@ class PrimeTable {
|
||||||
// Implementation #1 calculates the primes on-the-fly.
|
// Implementation #1 calculates the primes on-the-fly.
|
||||||
class OnTheFlyPrimeTable : public PrimeTable {
|
class OnTheFlyPrimeTable : public PrimeTable {
|
||||||
public:
|
public:
|
||||||
virtual bool IsPrime(int n) const {
|
bool IsPrime(int n) const override {
|
||||||
if (n <= 1) return false;
|
if (n <= 1) return false;
|
||||||
|
|
||||||
for (int i = 2; i*i <= n; i++) {
|
for (int i = 2; i*i <= n; i++) {
|
||||||
|
@ -66,12 +65,12 @@ class OnTheFlyPrimeTable : public PrimeTable {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int GetNextPrime(int p) const {
|
int GetNextPrime(int p) const override {
|
||||||
for (int n = p + 1; n > 0; n++) {
|
if (p < 0) return -1;
|
||||||
|
|
||||||
|
for (int n = p + 1;; n++) {
|
||||||
if (IsPrime(n)) return n;
|
if (IsPrime(n)) return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,13 +83,13 @@ class PreCalculatedPrimeTable : public PrimeTable {
|
||||||
: is_prime_size_(max + 1), is_prime_(new bool[max + 1]) {
|
: is_prime_size_(max + 1), is_prime_(new bool[max + 1]) {
|
||||||
CalculatePrimesUpTo(max);
|
CalculatePrimesUpTo(max);
|
||||||
}
|
}
|
||||||
virtual ~PreCalculatedPrimeTable() { delete[] is_prime_; }
|
~PreCalculatedPrimeTable() override { delete[] is_prime_; }
|
||||||
|
|
||||||
virtual bool IsPrime(int n) const {
|
bool IsPrime(int n) const override {
|
||||||
return 0 <= n && n < is_prime_size_ && is_prime_[n];
|
return 0 <= n && n < is_prime_size_ && is_prime_[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int GetNextPrime(int p) const {
|
int GetNextPrime(int p) const override {
|
||||||
for (int n = p + 1; n < is_prime_size_; n++) {
|
for (int n = p + 1; n < is_prime_size_; n++) {
|
||||||
if (is_prime_[n]) return n;
|
if (is_prime_[n]) return n;
|
||||||
}
|
}
|
||||||
|
@ -103,11 +102,15 @@ class PreCalculatedPrimeTable : public PrimeTable {
|
||||||
::std::fill(is_prime_, is_prime_ + is_prime_size_, true);
|
::std::fill(is_prime_, is_prime_ + is_prime_size_, true);
|
||||||
is_prime_[0] = is_prime_[1] = false;
|
is_prime_[0] = is_prime_[1] = false;
|
||||||
|
|
||||||
for (int i = 2; i <= max; i++) {
|
// Checks every candidate for prime number (we know that 2 is the only even
|
||||||
|
// prime).
|
||||||
|
for (int i = 2; i*i <= max; i += i%2+1) {
|
||||||
if (!is_prime_[i]) continue;
|
if (!is_prime_[i]) continue;
|
||||||
|
|
||||||
// Marks all multiples of i (except i itself) as non-prime.
|
// Marks all multiples of i (except i itself) as non-prime.
|
||||||
for (int j = 2*i; j <= max; j += i) {
|
// We are starting here from i-th multiplier, because all smaller
|
||||||
|
// complex numbers were already marked.
|
||||||
|
for (int j = i*i; j <= max; j += i) {
|
||||||
is_prime_[j] = false;
|
is_prime_[j] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,4 +123,4 @@ class PreCalculatedPrimeTable : public PrimeTable {
|
||||||
void operator=(const PreCalculatedPrimeTable& rhs);
|
void operator=(const PreCalculatedPrimeTable& rhs);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GTEST_SAMPLES_PRIME_TABLES_H_
|
#endif // GOOGLETEST_SAMPLES_PRIME_TABLES_H_
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
#include "sample1.h"
|
#include "sample1.h"
|
||||||
|
|
||||||
|
@ -43,7 +41,7 @@ int Factorial(int n) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff n is a prime number.
|
// Returns true if and only if n is a prime number.
|
||||||
bool IsPrime(int n) {
|
bool IsPrime(int n) {
|
||||||
// Trivial case 1: small numbers
|
// Trivial case 1: small numbers
|
||||||
if (n <= 1) return false;
|
if (n <= 1) return false;
|
||||||
|
@ -55,7 +53,7 @@ bool IsPrime(int n) {
|
||||||
|
|
||||||
// Try to divide n by every odd number i, starting from 3
|
// Try to divide n by every odd number i, starting from 3
|
||||||
for (int i = 3; ; i += 2) {
|
for (int i = 3; ; i += 2) {
|
||||||
// We only have to try i up to the squre root of n
|
// We only have to try i up to the square root of n
|
||||||
if (i > n/i) break;
|
if (i > n/i) break;
|
||||||
|
|
||||||
// Now, we have i <= n/i < n.
|
// Now, we have i <= n/i < n.
|
||||||
|
|
|
@ -28,16 +28,14 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
#ifndef GTEST_SAMPLES_SAMPLE1_H_
|
#ifndef GOOGLETEST_SAMPLES_SAMPLE1_H_
|
||||||
#define GTEST_SAMPLES_SAMPLE1_H_
|
#define GOOGLETEST_SAMPLES_SAMPLE1_H_
|
||||||
|
|
||||||
// Returns n! (the factorial of n). For negative n, n! is defined to be 1.
|
// Returns n! (the factorial of n). For negative n, n! is defined to be 1.
|
||||||
int Factorial(int n);
|
int Factorial(int n);
|
||||||
|
|
||||||
// Returns true iff n is a prime number.
|
// Returns true if and only if n is a prime number.
|
||||||
bool IsPrime(int n);
|
bool IsPrime(int n);
|
||||||
|
|
||||||
#endif // GTEST_SAMPLES_SAMPLE1_H_
|
#endif // GOOGLETEST_SAMPLES_SAMPLE1_H_
|
||||||
|
|
|
@ -25,8 +25,7 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
|
||||||
// Author: vladl@google.com (Vlad Losev)
|
|
||||||
|
|
||||||
// This sample shows how to use Google Test listener API to implement
|
// This sample shows how to use Google Test listener API to implement
|
||||||
// a primitive leak checker.
|
// a primitive leak checker.
|
||||||
|
@ -35,18 +34,15 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
using ::testing::EmptyTestEventListener;
|
using ::testing::EmptyTestEventListener;
|
||||||
using ::testing::InitGoogleTest;
|
using ::testing::InitGoogleTest;
|
||||||
using ::testing::Test;
|
using ::testing::Test;
|
||||||
using ::testing::TestCase;
|
|
||||||
using ::testing::TestEventListeners;
|
using ::testing::TestEventListeners;
|
||||||
using ::testing::TestInfo;
|
using ::testing::TestInfo;
|
||||||
using ::testing::TestPartResult;
|
using ::testing::TestPartResult;
|
||||||
using ::testing::UnitTest;
|
using ::testing::UnitTest;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// We will track memory used by this class.
|
// We will track memory used by this class.
|
||||||
class Water {
|
class Water {
|
||||||
public:
|
public:
|
||||||
|
@ -78,12 +74,12 @@ int Water::allocated_ = 0;
|
||||||
class LeakChecker : public EmptyTestEventListener {
|
class LeakChecker : public EmptyTestEventListener {
|
||||||
private:
|
private:
|
||||||
// Called before a test starts.
|
// Called before a test starts.
|
||||||
virtual void OnTestStart(const TestInfo& /* test_info */) {
|
void OnTestStart(const TestInfo& /* test_info */) override {
|
||||||
initially_allocated_ = Water::allocated();
|
initially_allocated_ = Water::allocated();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called after a test ends.
|
// Called after a test ends.
|
||||||
virtual void OnTestEnd(const TestInfo& /* test_info */) {
|
void OnTestEnd(const TestInfo& /* test_info */) override {
|
||||||
int difference = Water::allocated() - initially_allocated_;
|
int difference = Water::allocated() - initially_allocated_;
|
||||||
|
|
||||||
// You can generate a failure in any event handler except
|
// You can generate a failure in any event handler except
|
||||||
|
@ -104,9 +100,8 @@ TEST(ListenersTest, DoesNotLeak) {
|
||||||
// specified.
|
// specified.
|
||||||
TEST(ListenersTest, LeaksWater) {
|
TEST(ListenersTest, LeaksWater) {
|
||||||
Water* water = new Water;
|
Water* water = new Water;
|
||||||
EXPECT_TRUE(water != NULL);
|
EXPECT_TRUE(water != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
|
|
||||||
// This sample shows how to write a simple unit test for a function,
|
// This sample shows how to write a simple unit test for a function,
|
||||||
// using Google C++ testing framework.
|
// using Google C++ testing framework.
|
||||||
|
@ -46,7 +43,7 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "sample1.h"
|
#include "sample1.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
namespace {
|
||||||
|
|
||||||
// Step 2. Use the TEST macro to define your tests.
|
// Step 2. Use the TEST macro to define your tests.
|
||||||
//
|
//
|
||||||
|
@ -139,6 +136,7 @@ TEST(IsPrimeTest, Positive) {
|
||||||
EXPECT_FALSE(IsPrime(6));
|
EXPECT_FALSE(IsPrime(6));
|
||||||
EXPECT_TRUE(IsPrime(23));
|
EXPECT_TRUE(IsPrime(23));
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// Step 3. Call RUN_ALL_TESTS() in main().
|
// Step 3. Call RUN_ALL_TESTS() in main().
|
||||||
//
|
//
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
#include "sample2.h"
|
#include "sample2.h"
|
||||||
|
|
||||||
|
@ -37,7 +35,7 @@
|
||||||
|
|
||||||
// Clones a 0-terminated C string, allocating memory using new.
|
// Clones a 0-terminated C string, allocating memory using new.
|
||||||
const char* MyString::CloneCString(const char* a_c_string) {
|
const char* MyString::CloneCString(const char* a_c_string) {
|
||||||
if (a_c_string == NULL) return NULL;
|
if (a_c_string == nullptr) return nullptr;
|
||||||
|
|
||||||
const size_t len = strlen(a_c_string);
|
const size_t len = strlen(a_c_string);
|
||||||
char* const clone = new char[ len + 1 ];
|
char* const clone = new char[ len + 1 ];
|
||||||
|
|
|
@ -28,11 +28,9 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
#ifndef GTEST_SAMPLES_SAMPLE2_H_
|
#ifndef GOOGLETEST_SAMPLES_SAMPLE2_H_
|
||||||
#define GTEST_SAMPLES_SAMPLE2_H_
|
#define GOOGLETEST_SAMPLES_SAMPLE2_H_
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -52,15 +50,15 @@ class MyString {
|
||||||
// C'tors
|
// C'tors
|
||||||
|
|
||||||
// The default c'tor constructs a NULL string.
|
// The default c'tor constructs a NULL string.
|
||||||
MyString() : c_string_(NULL) {}
|
MyString() : c_string_(nullptr) {}
|
||||||
|
|
||||||
// Constructs a MyString by cloning a 0-terminated C string.
|
// Constructs a MyString by cloning a 0-terminated C string.
|
||||||
explicit MyString(const char* a_c_string) : c_string_(NULL) {
|
explicit MyString(const char* a_c_string) : c_string_(nullptr) {
|
||||||
Set(a_c_string);
|
Set(a_c_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy c'tor
|
// Copy c'tor
|
||||||
MyString(const MyString& string) : c_string_(NULL) {
|
MyString(const MyString& string) : c_string_(nullptr) {
|
||||||
Set(string.c_string_);
|
Set(string.c_string_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,13 +71,10 @@ class MyString {
|
||||||
// Gets the 0-terminated C string this MyString object represents.
|
// Gets the 0-terminated C string this MyString object represents.
|
||||||
const char* c_string() const { return c_string_; }
|
const char* c_string() const { return c_string_; }
|
||||||
|
|
||||||
size_t Length() const {
|
size_t Length() const { return c_string_ == nullptr ? 0 : strlen(c_string_); }
|
||||||
return c_string_ == NULL ? 0 : strlen(c_string_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the 0-terminated C string this MyString object represents.
|
// Sets the 0-terminated C string this MyString object represents.
|
||||||
void Set(const char* c_string);
|
void Set(const char* c_string);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // GOOGLETEST_SAMPLES_SAMPLE2_H_
|
||||||
#endif // GTEST_SAMPLES_SAMPLE2_H_
|
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
|
|
||||||
// This sample shows how to write a more complex unit test for a class
|
// This sample shows how to write a more complex unit test for a class
|
||||||
// that has multiple member functions.
|
// that has multiple member functions.
|
||||||
|
@ -42,7 +39,7 @@
|
||||||
|
|
||||||
#include "sample2.h"
|
#include "sample2.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
namespace {
|
||||||
// In this example, we test the MyString class (a simple string).
|
// In this example, we test the MyString class (a simple string).
|
||||||
|
|
||||||
// Tests the default c'tor.
|
// Tests the default c'tor.
|
||||||
|
@ -69,7 +66,7 @@ TEST(MyString, DefaultConstructor) {
|
||||||
// we have to live with this fact.
|
// we have to live with this fact.
|
||||||
//
|
//
|
||||||
// </TechnicalDetails>
|
// </TechnicalDetails>
|
||||||
EXPECT_STREQ(NULL, s.c_string());
|
EXPECT_STREQ(nullptr, s.c_string());
|
||||||
|
|
||||||
EXPECT_EQ(0u, s.Length());
|
EXPECT_EQ(0u, s.Length());
|
||||||
}
|
}
|
||||||
|
@ -104,6 +101,7 @@ TEST(MyString, Set) {
|
||||||
EXPECT_EQ(0, strcmp(s.c_string(), kHelloString));
|
EXPECT_EQ(0, strcmp(s.c_string(), kHelloString));
|
||||||
|
|
||||||
// Can we set the MyString to NULL?
|
// Can we set the MyString to NULL?
|
||||||
s.Set(NULL);
|
s.Set(nullptr);
|
||||||
EXPECT_STREQ(NULL, s.c_string());
|
EXPECT_STREQ(nullptr, s.c_string());
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
|
@ -28,11 +28,9 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
#ifndef GTEST_SAMPLES_SAMPLE3_INL_H_
|
#ifndef GOOGLETEST_SAMPLES_SAMPLE3_INL_H_
|
||||||
#define GTEST_SAMPLES_SAMPLE3_INL_H_
|
#define GOOGLETEST_SAMPLES_SAMPLE3_INL_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
@ -60,7 +58,8 @@ class QueueNode {
|
||||||
private:
|
private:
|
||||||
// Creates a node with a given element value. The next pointer is
|
// Creates a node with a given element value. The next pointer is
|
||||||
// set to NULL.
|
// set to NULL.
|
||||||
explicit QueueNode(const E& an_element) : element_(an_element), next_(NULL) {}
|
explicit QueueNode(const E& an_element)
|
||||||
|
: element_(an_element), next_(nullptr) {}
|
||||||
|
|
||||||
// We disable the default assignment operator and copy c'tor.
|
// We disable the default assignment operator and copy c'tor.
|
||||||
const QueueNode& operator = (const QueueNode&);
|
const QueueNode& operator = (const QueueNode&);
|
||||||
|
@ -74,7 +73,7 @@ template <typename E> // E is the element type.
|
||||||
class Queue {
|
class Queue {
|
||||||
public:
|
public:
|
||||||
// Creates an empty queue.
|
// Creates an empty queue.
|
||||||
Queue() : head_(NULL), last_(NULL), size_(0) {}
|
Queue() : head_(nullptr), last_(nullptr), size_(0) {}
|
||||||
|
|
||||||
// D'tor. Clears the queue.
|
// D'tor. Clears the queue.
|
||||||
~Queue() { Clear(); }
|
~Queue() { Clear(); }
|
||||||
|
@ -88,12 +87,12 @@ class Queue {
|
||||||
for (; ;) {
|
for (; ;) {
|
||||||
delete node;
|
delete node;
|
||||||
node = next;
|
node = next;
|
||||||
if (node == NULL) break;
|
if (node == nullptr) break;
|
||||||
next = node->next();
|
next = node->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Resets the member variables.
|
// 2. Resets the member variables.
|
||||||
head_ = last_ = NULL;
|
head_ = last_ = nullptr;
|
||||||
size_ = 0;
|
size_ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,14 +129,14 @@ class Queue {
|
||||||
// the queue is empty.
|
// the queue is empty.
|
||||||
E* Dequeue() {
|
E* Dequeue() {
|
||||||
if (size_ == 0) {
|
if (size_ == 0) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QueueNode<E>* const old_head = head_;
|
const QueueNode<E>* const old_head = head_;
|
||||||
head_ = head_->next_;
|
head_ = head_->next_;
|
||||||
size_--;
|
size_--;
|
||||||
if (size_ == 0) {
|
if (size_ == 0) {
|
||||||
last_ = NULL;
|
last_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
E* element = new E(old_head->element());
|
E* element = new E(old_head->element());
|
||||||
|
@ -152,7 +151,8 @@ class Queue {
|
||||||
template <typename F>
|
template <typename F>
|
||||||
Queue* Map(F function) const {
|
Queue* Map(F function) const {
|
||||||
Queue* new_queue = new Queue();
|
Queue* new_queue = new Queue();
|
||||||
for (const QueueNode<E>* node = head_; node != NULL; node = node->next_) {
|
for (const QueueNode<E>* node = head_; node != nullptr;
|
||||||
|
node = node->next_) {
|
||||||
new_queue->Enqueue(function(node->element()));
|
new_queue->Enqueue(function(node->element()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,4 +169,4 @@ class Queue {
|
||||||
const Queue& operator = (const Queue&);
|
const Queue& operator = (const Queue&);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GTEST_SAMPLES_SAMPLE3_INL_H_
|
#endif // GOOGLETEST_SAMPLES_SAMPLE3_INL_H_
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
|
|
||||||
// In this example, we use a more advanced feature of Google Test called
|
// In this example, we use a more advanced feature of Google Test called
|
||||||
// test fixture.
|
// test fixture.
|
||||||
|
@ -65,16 +62,16 @@
|
||||||
|
|
||||||
#include "sample3-inl.h"
|
#include "sample3-inl.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
namespace {
|
||||||
// To use a test fixture, derive a class from testing::Test.
|
// To use a test fixture, derive a class from testing::Test.
|
||||||
class QueueTest : public testing::Test {
|
class QueueTestSmpl3 : public testing::Test {
|
||||||
protected: // You should make the members protected s.t. they can be
|
protected: // You should make the members protected s.t. they can be
|
||||||
// accessed from sub-classes.
|
// accessed from sub-classes.
|
||||||
|
|
||||||
// virtual void SetUp() will be called before each test is run. You
|
// virtual void SetUp() will be called before each test is run. You
|
||||||
// should define it if you need to initialize the varaibles.
|
// should define it if you need to initialize the variables.
|
||||||
// Otherwise, this can be skipped.
|
// Otherwise, this can be skipped.
|
||||||
virtual void SetUp() {
|
void SetUp() override {
|
||||||
q1_.Enqueue(1);
|
q1_.Enqueue(1);
|
||||||
q2_.Enqueue(2);
|
q2_.Enqueue(2);
|
||||||
q2_.Enqueue(3);
|
q2_.Enqueue(3);
|
||||||
|
@ -102,8 +99,8 @@ class QueueTest : public testing::Test {
|
||||||
ASSERT_EQ(q->Size(), new_q->Size());
|
ASSERT_EQ(q->Size(), new_q->Size());
|
||||||
|
|
||||||
// Verifies the relationship between the elements of the two queues.
|
// Verifies the relationship between the elements of the two queues.
|
||||||
for ( const QueueNode<int> * n1 = q->Head(), * n2 = new_q->Head();
|
for (const QueueNode<int>*n1 = q->Head(), *n2 = new_q->Head();
|
||||||
n1 != NULL; n1 = n1->next(), n2 = n2->next() ) {
|
n1 != nullptr; n1 = n1->next(), n2 = n2->next()) {
|
||||||
EXPECT_EQ(2 * n1->element(), n2->element());
|
EXPECT_EQ(2 * n1->element(), n2->element());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,32 +117,33 @@ class QueueTest : public testing::Test {
|
||||||
// instead of TEST.
|
// instead of TEST.
|
||||||
|
|
||||||
// Tests the default c'tor.
|
// Tests the default c'tor.
|
||||||
TEST_F(QueueTest, DefaultConstructor) {
|
TEST_F(QueueTestSmpl3, DefaultConstructor) {
|
||||||
// You can access data in the test fixture here.
|
// You can access data in the test fixture here.
|
||||||
EXPECT_EQ(0u, q0_.Size());
|
EXPECT_EQ(0u, q0_.Size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests Dequeue().
|
// Tests Dequeue().
|
||||||
TEST_F(QueueTest, Dequeue) {
|
TEST_F(QueueTestSmpl3, Dequeue) {
|
||||||
int * n = q0_.Dequeue();
|
int * n = q0_.Dequeue();
|
||||||
EXPECT_TRUE(n == NULL);
|
EXPECT_TRUE(n == nullptr);
|
||||||
|
|
||||||
n = q1_.Dequeue();
|
n = q1_.Dequeue();
|
||||||
ASSERT_TRUE(n != NULL);
|
ASSERT_TRUE(n != nullptr);
|
||||||
EXPECT_EQ(1, *n);
|
EXPECT_EQ(1, *n);
|
||||||
EXPECT_EQ(0u, q1_.Size());
|
EXPECT_EQ(0u, q1_.Size());
|
||||||
delete n;
|
delete n;
|
||||||
|
|
||||||
n = q2_.Dequeue();
|
n = q2_.Dequeue();
|
||||||
ASSERT_TRUE(n != NULL);
|
ASSERT_TRUE(n != nullptr);
|
||||||
EXPECT_EQ(2, *n);
|
EXPECT_EQ(2, *n);
|
||||||
EXPECT_EQ(1u, q2_.Size());
|
EXPECT_EQ(1u, q2_.Size());
|
||||||
delete n;
|
delete n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests the Queue::Map() function.
|
// Tests the Queue::Map() function.
|
||||||
TEST_F(QueueTest, Map) {
|
TEST_F(QueueTestSmpl3, Map) {
|
||||||
MapTester(&q0_);
|
MapTester(&q0_);
|
||||||
MapTester(&q1_);
|
MapTester(&q1_);
|
||||||
MapTester(&q2_);
|
MapTester(&q2_);
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
@ -40,6 +38,16 @@ int Counter::Increment() {
|
||||||
return counter_++;
|
return counter_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the current counter value, and decrements it.
|
||||||
|
// counter can not be less than 0, return 0 in this case
|
||||||
|
int Counter::Decrement() {
|
||||||
|
if (counter_ == 0) {
|
||||||
|
return counter_;
|
||||||
|
} else {
|
||||||
|
return counter_--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Prints the current counter value to STDOUT.
|
// Prints the current counter value to STDOUT.
|
||||||
void Counter::Print() const {
|
void Counter::Print() const {
|
||||||
printf("%d", counter_);
|
printf("%d", counter_);
|
||||||
|
|
|
@ -28,11 +28,8 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// A sample program demonstrating using Google C++ testing framework.
|
// A sample program demonstrating using Google C++ testing framework.
|
||||||
//
|
#ifndef GOOGLETEST_SAMPLES_SAMPLE4_H_
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
#define GOOGLETEST_SAMPLES_SAMPLE4_H_
|
||||||
|
|
||||||
#ifndef GTEST_SAMPLES_SAMPLE4_H_
|
|
||||||
#define GTEST_SAMPLES_SAMPLE4_H_
|
|
||||||
|
|
||||||
// A simple monotonic counter.
|
// A simple monotonic counter.
|
||||||
class Counter {
|
class Counter {
|
||||||
|
@ -46,8 +43,11 @@ class Counter {
|
||||||
// Returns the current counter value, and increments it.
|
// Returns the current counter value, and increments it.
|
||||||
int Increment();
|
int Increment();
|
||||||
|
|
||||||
|
// Returns the current counter value, and decrements it.
|
||||||
|
int Decrement();
|
||||||
|
|
||||||
// Prints the current counter value to STDOUT.
|
// Prints the current counter value to STDOUT.
|
||||||
void Print() const;
|
void Print() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GTEST_SAMPLES_SAMPLE4_H_
|
#endif // GOOGLETEST_SAMPLES_SAMPLE4_H_
|
||||||
|
|
|
@ -26,20 +26,28 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
#include "sample4.h"
|
#include "sample4.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
// Tests the Increment() method.
|
// Tests the Increment() method.
|
||||||
|
|
||||||
TEST(Counter, Increment) {
|
TEST(Counter, Increment) {
|
||||||
Counter c;
|
Counter c;
|
||||||
|
|
||||||
|
// Test that counter 0 returns 0
|
||||||
|
EXPECT_EQ(0, c.Decrement());
|
||||||
|
|
||||||
// EXPECT_EQ() evaluates its arguments exactly once, so they
|
// EXPECT_EQ() evaluates its arguments exactly once, so they
|
||||||
// can have side effects.
|
// can have side effects.
|
||||||
|
|
||||||
EXPECT_EQ(0, c.Increment());
|
EXPECT_EQ(0, c.Increment());
|
||||||
EXPECT_EQ(1, c.Increment());
|
EXPECT_EQ(1, c.Increment());
|
||||||
EXPECT_EQ(2, c.Increment());
|
EXPECT_EQ(2, c.Increment());
|
||||||
|
|
||||||
|
EXPECT_EQ(3, c.Decrement());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
|
@ -26,8 +26,7 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
// This sample teaches how to reuse a test fixture in multiple test
|
// This sample teaches how to reuse a test fixture in multiple test
|
||||||
// cases by deriving sub-fixtures from it.
|
// cases by deriving sub-fixtures from it.
|
||||||
|
@ -46,10 +45,10 @@
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "sample3-inl.h"
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "sample1.h"
|
#include "sample1.h"
|
||||||
|
#include "sample3-inl.h"
|
||||||
|
namespace {
|
||||||
// In this sample, we want to ensure that every test finishes within
|
// In this sample, we want to ensure that every test finishes within
|
||||||
// ~5 seconds. If a test takes longer to run, we consider it a
|
// ~5 seconds. If a test takes longer to run, we consider it a
|
||||||
// failure.
|
// failure.
|
||||||
|
@ -64,15 +63,13 @@ class QuickTest : public testing::Test {
|
||||||
protected:
|
protected:
|
||||||
// Remember that SetUp() is run immediately before a test starts.
|
// Remember that SetUp() is run immediately before a test starts.
|
||||||
// This is a good place to record the start time.
|
// This is a good place to record the start time.
|
||||||
virtual void SetUp() {
|
void SetUp() override { start_time_ = time(nullptr); }
|
||||||
start_time_ = time(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TearDown() is invoked immediately after a test finishes. Here we
|
// TearDown() is invoked immediately after a test finishes. Here we
|
||||||
// check if the test was too slow.
|
// check if the test was too slow.
|
||||||
virtual void TearDown() {
|
void TearDown() override {
|
||||||
// Gets the time when the test finishes
|
// Gets the time when the test finishes
|
||||||
const time_t end_time = time(NULL);
|
const time_t end_time = time(nullptr);
|
||||||
|
|
||||||
// Asserts that the test took no more than ~5 seconds. Did you
|
// Asserts that the test took no more than ~5 seconds. Did you
|
||||||
// know that you can use assertions in SetUp() and TearDown() as
|
// know that you can use assertions in SetUp() and TearDown() as
|
||||||
|
@ -143,7 +140,7 @@ TEST_F(IntegerFunctionTest, IsPrime) {
|
||||||
// stuff inside the body of the test fixture, as usual.
|
// stuff inside the body of the test fixture, as usual.
|
||||||
class QueueTest : public QuickTest {
|
class QueueTest : public QuickTest {
|
||||||
protected:
|
protected:
|
||||||
virtual void SetUp() {
|
void SetUp() override {
|
||||||
// First, we need to set up the super fixture (QuickTest).
|
// First, we need to set up the super fixture (QuickTest).
|
||||||
QuickTest::SetUp();
|
QuickTest::SetUp();
|
||||||
|
|
||||||
|
@ -177,21 +174,21 @@ TEST_F(QueueTest, DefaultConstructor) {
|
||||||
// Tests Dequeue().
|
// Tests Dequeue().
|
||||||
TEST_F(QueueTest, Dequeue) {
|
TEST_F(QueueTest, Dequeue) {
|
||||||
int* n = q0_.Dequeue();
|
int* n = q0_.Dequeue();
|
||||||
EXPECT_TRUE(n == NULL);
|
EXPECT_TRUE(n == nullptr);
|
||||||
|
|
||||||
n = q1_.Dequeue();
|
n = q1_.Dequeue();
|
||||||
EXPECT_TRUE(n != NULL);
|
EXPECT_TRUE(n != nullptr);
|
||||||
EXPECT_EQ(1, *n);
|
EXPECT_EQ(1, *n);
|
||||||
EXPECT_EQ(0u, q1_.Size());
|
EXPECT_EQ(0u, q1_.Size());
|
||||||
delete n;
|
delete n;
|
||||||
|
|
||||||
n = q2_.Dequeue();
|
n = q2_.Dequeue();
|
||||||
EXPECT_TRUE(n != NULL);
|
EXPECT_TRUE(n != nullptr);
|
||||||
EXPECT_EQ(2, *n);
|
EXPECT_EQ(2, *n);
|
||||||
EXPECT_EQ(1u, q2_.Size());
|
EXPECT_EQ(1u, q2_.Size());
|
||||||
delete n;
|
delete n;
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
// If necessary, you can derive further test fixtures from a derived
|
// If necessary, you can derive further test fixtures from a derived
|
||||||
// fixture itself. For example, you can derive another fixture from
|
// fixture itself. For example, you can derive another fixture from
|
||||||
// QueueTest. Google Test imposes no limit on how deep the hierarchy
|
// QueueTest. Google Test imposes no limit on how deep the hierarchy
|
||||||
|
|
|
@ -26,8 +26,7 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
|
|
||||||
// This sample shows how to test common properties of multiple
|
// This sample shows how to test common properties of multiple
|
||||||
// implementations of the same interface (aka interface tests).
|
// implementations of the same interface (aka interface tests).
|
||||||
|
@ -36,7 +35,7 @@
|
||||||
#include "prime_tables.h"
|
#include "prime_tables.h"
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
namespace {
|
||||||
// First, we define some factory functions for creating instances of
|
// First, we define some factory functions for creating instances of
|
||||||
// the implementations. You may be able to skip this step if all your
|
// the implementations. You may be able to skip this step if all your
|
||||||
// implementations can be constructed the same way.
|
// implementations can be constructed the same way.
|
||||||
|
@ -62,7 +61,7 @@ class PrimeTableTest : public testing::Test {
|
||||||
// implemented by T.
|
// implemented by T.
|
||||||
PrimeTableTest() : table_(CreatePrimeTable<T>()) {}
|
PrimeTableTest() : table_(CreatePrimeTable<T>()) {}
|
||||||
|
|
||||||
virtual ~PrimeTableTest() { delete table_; }
|
~PrimeTableTest() override { delete table_; }
|
||||||
|
|
||||||
// Note that we test an implementation via the base interface
|
// Note that we test an implementation via the base interface
|
||||||
// instead of the actual implementation class. This is important
|
// instead of the actual implementation class. This is important
|
||||||
|
@ -74,8 +73,6 @@ class PrimeTableTest : public testing::Test {
|
||||||
PrimeTable* const table_;
|
PrimeTable* const table_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if GTEST_HAS_TYPED_TEST
|
|
||||||
|
|
||||||
using testing::Types;
|
using testing::Types;
|
||||||
|
|
||||||
// Google Test offers two ways for reusing tests for different types.
|
// Google Test offers two ways for reusing tests for different types.
|
||||||
|
@ -85,7 +82,7 @@ using testing::Types;
|
||||||
|
|
||||||
// To write a typed test case, first use
|
// To write a typed test case, first use
|
||||||
//
|
//
|
||||||
// TYPED_TEST_CASE(TestCaseName, TypeList);
|
// TYPED_TEST_SUITE(TestCaseName, TypeList);
|
||||||
//
|
//
|
||||||
// to declare it and specify the type parameters. As with TEST_F,
|
// to declare it and specify the type parameters. As with TEST_F,
|
||||||
// TestCaseName must match the test fixture name.
|
// TestCaseName must match the test fixture name.
|
||||||
|
@ -93,7 +90,7 @@ using testing::Types;
|
||||||
// The list of types we want to test.
|
// The list of types we want to test.
|
||||||
typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable> Implementations;
|
typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable> Implementations;
|
||||||
|
|
||||||
TYPED_TEST_CASE(PrimeTableTest, Implementations);
|
TYPED_TEST_SUITE(PrimeTableTest, Implementations);
|
||||||
|
|
||||||
// Then use TYPED_TEST(TestCaseName, TestName) to define a typed test,
|
// Then use TYPED_TEST(TestCaseName, TestName) to define a typed test,
|
||||||
// similar to TEST_F.
|
// similar to TEST_F.
|
||||||
|
@ -132,13 +129,9 @@ TYPED_TEST(PrimeTableTest, CanGetNextPrime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// That's it! Google Test will repeat each TYPED_TEST for each type
|
// That's it! Google Test will repeat each TYPED_TEST for each type
|
||||||
// in the type list specified in TYPED_TEST_CASE. Sit back and be
|
// in the type list specified in TYPED_TEST_SUITE. Sit back and be
|
||||||
// happy that you don't have to define them multiple times.
|
// happy that you don't have to define them multiple times.
|
||||||
|
|
||||||
#endif // GTEST_HAS_TYPED_TEST
|
|
||||||
|
|
||||||
#if GTEST_HAS_TYPED_TEST_P
|
|
||||||
|
|
||||||
using testing::Types;
|
using testing::Types;
|
||||||
|
|
||||||
// Sometimes, however, you don't yet know all the types that you want
|
// Sometimes, however, you don't yet know all the types that you want
|
||||||
|
@ -164,7 +157,7 @@ class PrimeTableTest2 : public PrimeTableTest<T> {
|
||||||
// Then, declare the test case. The argument is the name of the test
|
// Then, declare the test case. The argument is the name of the test
|
||||||
// fixture, and also the name of the test case (as usual). The _P
|
// fixture, and also the name of the test case (as usual). The _P
|
||||||
// suffix is for "parameterized" or "pattern".
|
// suffix is for "parameterized" or "pattern".
|
||||||
TYPED_TEST_CASE_P(PrimeTableTest2);
|
TYPED_TEST_SUITE_P(PrimeTableTest2);
|
||||||
|
|
||||||
// Next, use TYPED_TEST_P(TestCaseName, TestName) to define a test,
|
// Next, use TYPED_TEST_P(TestCaseName, TestName) to define a test,
|
||||||
// similar to what you do with TEST_F.
|
// similar to what you do with TEST_F.
|
||||||
|
@ -197,7 +190,7 @@ TYPED_TEST_P(PrimeTableTest2, CanGetNextPrime) {
|
||||||
|
|
||||||
// Type-parameterized tests involve one extra step: you have to
|
// Type-parameterized tests involve one extra step: you have to
|
||||||
// enumerate the tests you defined:
|
// enumerate the tests you defined:
|
||||||
REGISTER_TYPED_TEST_CASE_P(
|
REGISTER_TYPED_TEST_SUITE_P(
|
||||||
PrimeTableTest2, // The first argument is the test case name.
|
PrimeTableTest2, // The first argument is the test case name.
|
||||||
// The rest of the arguments are the test names.
|
// The rest of the arguments are the test names.
|
||||||
ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime);
|
ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime);
|
||||||
|
@ -217,8 +210,8 @@ REGISTER_TYPED_TEST_CASE_P(
|
||||||
// defined at the time we write the TYPED_TEST_P()s.
|
// defined at the time we write the TYPED_TEST_P()s.
|
||||||
typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable>
|
typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable>
|
||||||
PrimeTableImplementations;
|
PrimeTableImplementations;
|
||||||
INSTANTIATE_TYPED_TEST_CASE_P(OnTheFlyAndPreCalculated, // Instance name
|
INSTANTIATE_TYPED_TEST_SUITE_P(OnTheFlyAndPreCalculated, // Instance name
|
||||||
PrimeTableTest2, // Test case name
|
PrimeTableTest2, // Test case name
|
||||||
PrimeTableImplementations); // Type list
|
PrimeTableImplementations); // Type list
|
||||||
|
|
||||||
#endif // GTEST_HAS_TYPED_TEST_P
|
} // namespace
|
||||||
|
|
|
@ -26,8 +26,7 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
|
||||||
// Author: vladl@google.com (Vlad Losev)
|
|
||||||
|
|
||||||
// This sample shows how to test common properties of multiple
|
// This sample shows how to test common properties of multiple
|
||||||
// implementations of an interface (aka interface tests) using
|
// implementations of an interface (aka interface tests) using
|
||||||
|
@ -39,8 +38,7 @@
|
||||||
#include "prime_tables.h"
|
#include "prime_tables.h"
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
namespace {
|
||||||
#if GTEST_HAS_PARAM_TEST
|
|
||||||
|
|
||||||
using ::testing::TestWithParam;
|
using ::testing::TestWithParam;
|
||||||
using ::testing::Values;
|
using ::testing::Values;
|
||||||
|
@ -65,20 +63,20 @@ PrimeTable* CreatePreCalculatedPrimeTable() {
|
||||||
// can refer to the test parameter by GetParam(). In this case, the test
|
// can refer to the test parameter by GetParam(). In this case, the test
|
||||||
// parameter is a factory function which we call in fixture's SetUp() to
|
// parameter is a factory function which we call in fixture's SetUp() to
|
||||||
// create and store an instance of PrimeTable.
|
// create and store an instance of PrimeTable.
|
||||||
class PrimeTableTest : public TestWithParam<CreatePrimeTableFunc*> {
|
class PrimeTableTestSmpl7 : public TestWithParam<CreatePrimeTableFunc*> {
|
||||||
public:
|
public:
|
||||||
virtual ~PrimeTableTest() { delete table_; }
|
~PrimeTableTestSmpl7() override { delete table_; }
|
||||||
virtual void SetUp() { table_ = (*GetParam())(); }
|
void SetUp() override { table_ = (*GetParam())(); }
|
||||||
virtual void TearDown() {
|
void TearDown() override {
|
||||||
delete table_;
|
delete table_;
|
||||||
table_ = NULL;
|
table_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PrimeTable* table_;
|
PrimeTable* table_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) {
|
TEST_P(PrimeTableTestSmpl7, ReturnsFalseForNonPrimes) {
|
||||||
EXPECT_FALSE(table_->IsPrime(-5));
|
EXPECT_FALSE(table_->IsPrime(-5));
|
||||||
EXPECT_FALSE(table_->IsPrime(0));
|
EXPECT_FALSE(table_->IsPrime(0));
|
||||||
EXPECT_FALSE(table_->IsPrime(1));
|
EXPECT_FALSE(table_->IsPrime(1));
|
||||||
|
@ -87,7 +85,7 @@ TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) {
|
||||||
EXPECT_FALSE(table_->IsPrime(100));
|
EXPECT_FALSE(table_->IsPrime(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(PrimeTableTest, ReturnsTrueForPrimes) {
|
TEST_P(PrimeTableTestSmpl7, ReturnsTrueForPrimes) {
|
||||||
EXPECT_TRUE(table_->IsPrime(2));
|
EXPECT_TRUE(table_->IsPrime(2));
|
||||||
EXPECT_TRUE(table_->IsPrime(3));
|
EXPECT_TRUE(table_->IsPrime(3));
|
||||||
EXPECT_TRUE(table_->IsPrime(5));
|
EXPECT_TRUE(table_->IsPrime(5));
|
||||||
|
@ -96,7 +94,7 @@ TEST_P(PrimeTableTest, ReturnsTrueForPrimes) {
|
||||||
EXPECT_TRUE(table_->IsPrime(131));
|
EXPECT_TRUE(table_->IsPrime(131));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(PrimeTableTest, CanGetNextPrime) {
|
TEST_P(PrimeTableTestSmpl7, CanGetNextPrime) {
|
||||||
EXPECT_EQ(2, table_->GetNextPrime(0));
|
EXPECT_EQ(2, table_->GetNextPrime(0));
|
||||||
EXPECT_EQ(3, table_->GetNextPrime(2));
|
EXPECT_EQ(3, table_->GetNextPrime(2));
|
||||||
EXPECT_EQ(5, table_->GetNextPrime(3));
|
EXPECT_EQ(5, table_->GetNextPrime(3));
|
||||||
|
@ -112,19 +110,8 @@ TEST_P(PrimeTableTest, CanGetNextPrime) {
|
||||||
//
|
//
|
||||||
// Here, we instantiate our tests with a list of two PrimeTable object
|
// Here, we instantiate our tests with a list of two PrimeTable object
|
||||||
// factory functions:
|
// factory functions:
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_SUITE_P(OnTheFlyAndPreCalculated, PrimeTableTestSmpl7,
|
||||||
OnTheFlyAndPreCalculated,
|
Values(&CreateOnTheFlyPrimeTable,
|
||||||
PrimeTableTest,
|
&CreatePreCalculatedPrimeTable<1000>));
|
||||||
Values(&CreateOnTheFlyPrimeTable, &CreatePreCalculatedPrimeTable<1000>));
|
|
||||||
|
|
||||||
#else
|
} // namespace
|
||||||
|
|
||||||
// Google Test may not support value-parameterized tests with some
|
|
||||||
// compilers. If we use conditional compilation to compile out all
|
|
||||||
// code referring to the gtest_main library, MSVC linker will not link
|
|
||||||
// that library at all and consequently complain about missing entry
|
|
||||||
// point defined in that library (fatal error LNK1561: entry point
|
|
||||||
// must be defined). This dummy test keeps gtest_main linked in.
|
|
||||||
TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
|
|
||||||
|
|
||||||
#endif // GTEST_HAS_PARAM_TEST
|
|
||||||
|
|
|
@ -26,8 +26,7 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
|
||||||
// Author: vladl@google.com (Vlad Losev)
|
|
||||||
|
|
||||||
// This sample shows how to test code relying on some global flag variables.
|
// This sample shows how to test code relying on some global flag variables.
|
||||||
// Combine() helps with generating all possible combinations of such flags,
|
// Combine() helps with generating all possible combinations of such flags,
|
||||||
|
@ -37,8 +36,7 @@
|
||||||
#include "prime_tables.h"
|
#include "prime_tables.h"
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
namespace {
|
||||||
#if GTEST_HAS_COMBINE
|
|
||||||
|
|
||||||
// Suppose we want to introduce a new, improved implementation of PrimeTable
|
// Suppose we want to introduce a new, improved implementation of PrimeTable
|
||||||
// which combines speed of PrecalcPrimeTable and versatility of
|
// which combines speed of PrecalcPrimeTable and versatility of
|
||||||
|
@ -51,24 +49,25 @@ class HybridPrimeTable : public PrimeTable {
|
||||||
public:
|
public:
|
||||||
HybridPrimeTable(bool force_on_the_fly, int max_precalculated)
|
HybridPrimeTable(bool force_on_the_fly, int max_precalculated)
|
||||||
: on_the_fly_impl_(new OnTheFlyPrimeTable),
|
: on_the_fly_impl_(new OnTheFlyPrimeTable),
|
||||||
precalc_impl_(force_on_the_fly ? NULL :
|
precalc_impl_(force_on_the_fly
|
||||||
new PreCalculatedPrimeTable(max_precalculated)),
|
? nullptr
|
||||||
|
: new PreCalculatedPrimeTable(max_precalculated)),
|
||||||
max_precalculated_(max_precalculated) {}
|
max_precalculated_(max_precalculated) {}
|
||||||
virtual ~HybridPrimeTable() {
|
~HybridPrimeTable() override {
|
||||||
delete on_the_fly_impl_;
|
delete on_the_fly_impl_;
|
||||||
delete precalc_impl_;
|
delete precalc_impl_;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool IsPrime(int n) const {
|
bool IsPrime(int n) const override {
|
||||||
if (precalc_impl_ != NULL && n < max_precalculated_)
|
if (precalc_impl_ != nullptr && n < max_precalculated_)
|
||||||
return precalc_impl_->IsPrime(n);
|
return precalc_impl_->IsPrime(n);
|
||||||
else
|
else
|
||||||
return on_the_fly_impl_->IsPrime(n);
|
return on_the_fly_impl_->IsPrime(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int GetNextPrime(int p) const {
|
int GetNextPrime(int p) const override {
|
||||||
int next_prime = -1;
|
int next_prime = -1;
|
||||||
if (precalc_impl_ != NULL && p < max_precalculated_)
|
if (precalc_impl_ != nullptr && p < max_precalculated_)
|
||||||
next_prime = precalc_impl_->GetNextPrime(p);
|
next_prime = precalc_impl_->GetNextPrime(p);
|
||||||
|
|
||||||
return next_prime != -1 ? next_prime : on_the_fly_impl_->GetNextPrime(p);
|
return next_prime != -1 ? next_prime : on_the_fly_impl_->GetNextPrime(p);
|
||||||
|
@ -90,24 +89,17 @@ using ::testing::Combine;
|
||||||
// PreCalculatedPrimeTable disabled. We do this by defining fixture which will
|
// PreCalculatedPrimeTable disabled. We do this by defining fixture which will
|
||||||
// accept different combinations of parameters for instantiating a
|
// accept different combinations of parameters for instantiating a
|
||||||
// HybridPrimeTable instance.
|
// HybridPrimeTable instance.
|
||||||
class PrimeTableTest : public TestWithParam< ::testing::tuple<bool, int> > {
|
class PrimeTableTest : public TestWithParam< ::std::tuple<bool, int> > {
|
||||||
protected:
|
protected:
|
||||||
virtual void SetUp() {
|
void SetUp() override {
|
||||||
// This can be written as
|
bool force_on_the_fly;
|
||||||
//
|
int max_precalculated;
|
||||||
// bool force_on_the_fly;
|
std::tie(force_on_the_fly, max_precalculated) = GetParam();
|
||||||
// int max_precalculated;
|
|
||||||
// tie(force_on_the_fly, max_precalculated) = GetParam();
|
|
||||||
//
|
|
||||||
// once the Google C++ Style Guide allows use of ::std::tr1::tie.
|
|
||||||
//
|
|
||||||
bool force_on_the_fly = ::testing::get<0>(GetParam());
|
|
||||||
int max_precalculated = ::testing::get<1>(GetParam());
|
|
||||||
table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated);
|
table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated);
|
||||||
}
|
}
|
||||||
virtual void TearDown() {
|
void TearDown() override {
|
||||||
delete table_;
|
delete table_;
|
||||||
table_ = NULL;
|
table_ = nullptr;
|
||||||
}
|
}
|
||||||
HybridPrimeTable* table_;
|
HybridPrimeTable* table_;
|
||||||
};
|
};
|
||||||
|
@ -156,18 +148,7 @@ TEST_P(PrimeTableTest, CanGetNextPrime) {
|
||||||
// will put some of the tested numbers beyond the capability of the
|
// will put some of the tested numbers beyond the capability of the
|
||||||
// PrecalcPrimeTable instance and some inside it (10). Combine will produce all
|
// PrecalcPrimeTable instance and some inside it (10). Combine will produce all
|
||||||
// possible combinations.
|
// possible combinations.
|
||||||
INSTANTIATE_TEST_CASE_P(MeaningfulTestParameters,
|
INSTANTIATE_TEST_SUITE_P(MeaningfulTestParameters, PrimeTableTest,
|
||||||
PrimeTableTest,
|
Combine(Bool(), Values(1, 10)));
|
||||||
Combine(Bool(), Values(1, 10)));
|
|
||||||
|
|
||||||
#else
|
} // namespace
|
||||||
|
|
||||||
// Google Test may not support Combine() with some compilers. If we
|
|
||||||
// use conditional compilation to compile out all code referring to
|
|
||||||
// the gtest_main library, MSVC linker will not link that library at
|
|
||||||
// all and consequently complain about missing entry point defined in
|
|
||||||
// that library (fatal error LNK1561: entry point must be
|
|
||||||
// defined). This dummy test keeps gtest_main linked in.
|
|
||||||
TEST(DummyTest, CombineIsNotSupportedOnThisPlatform) {}
|
|
||||||
|
|
||||||
#endif // GTEST_HAS_COMBINE
|
|
||||||
|
|
|
@ -25,8 +25,7 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
|
||||||
// Author: vladl@google.com (Vlad Losev)
|
|
||||||
|
|
||||||
// This sample shows how to use Google Test listener API to implement
|
// This sample shows how to use Google Test listener API to implement
|
||||||
// an alternative console output and how to use the UnitTest reflection API
|
// an alternative console output and how to use the UnitTest reflection API
|
||||||
|
@ -44,24 +43,22 @@ using ::testing::TestEventListeners;
|
||||||
using ::testing::TestInfo;
|
using ::testing::TestInfo;
|
||||||
using ::testing::TestPartResult;
|
using ::testing::TestPartResult;
|
||||||
using ::testing::UnitTest;
|
using ::testing::UnitTest;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Provides alternative output mode which produces minimal amount of
|
// Provides alternative output mode which produces minimal amount of
|
||||||
// information about tests.
|
// information about tests.
|
||||||
class TersePrinter : public EmptyTestEventListener {
|
class TersePrinter : public EmptyTestEventListener {
|
||||||
private:
|
private:
|
||||||
// Called before any test activity starts.
|
// Called before any test activity starts.
|
||||||
virtual void OnTestProgramStart(const UnitTest& /* unit_test */) {}
|
void OnTestProgramStart(const UnitTest& /* unit_test */) override {}
|
||||||
|
|
||||||
// Called after all test activities have ended.
|
// Called after all test activities have ended.
|
||||||
virtual void OnTestProgramEnd(const UnitTest& unit_test) {
|
void OnTestProgramEnd(const UnitTest& unit_test) override {
|
||||||
fprintf(stdout, "TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED");
|
fprintf(stdout, "TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called before a test starts.
|
// Called before a test starts.
|
||||||
virtual void OnTestStart(const TestInfo& test_info) {
|
void OnTestStart(const TestInfo& test_info) override {
|
||||||
fprintf(stdout,
|
fprintf(stdout,
|
||||||
"*** Test %s.%s starting.\n",
|
"*** Test %s.%s starting.\n",
|
||||||
test_info.test_case_name(),
|
test_info.test_case_name(),
|
||||||
|
@ -70,7 +67,7 @@ class TersePrinter : public EmptyTestEventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called after a failed assertion or a SUCCEED() invocation.
|
// Called after a failed assertion or a SUCCEED() invocation.
|
||||||
virtual void OnTestPartResult(const TestPartResult& test_part_result) {
|
void OnTestPartResult(const TestPartResult& test_part_result) override {
|
||||||
fprintf(stdout,
|
fprintf(stdout,
|
||||||
"%s in %s:%d\n%s\n",
|
"%s in %s:%d\n%s\n",
|
||||||
test_part_result.failed() ? "*** Failure" : "Success",
|
test_part_result.failed() ? "*** Failure" : "Success",
|
||||||
|
@ -81,7 +78,7 @@ class TersePrinter : public EmptyTestEventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called after a test ends.
|
// Called after a test ends.
|
||||||
virtual void OnTestEnd(const TestInfo& test_info) {
|
void OnTestEnd(const TestInfo& test_info) override {
|
||||||
fprintf(stdout,
|
fprintf(stdout,
|
||||||
"*** Test %s.%s ending.\n",
|
"*** Test %s.%s ending.\n",
|
||||||
test_info.test_case_name(),
|
test_info.test_case_name(),
|
||||||
|
@ -102,7 +99,6 @@ TEST(CustomOutputTest, Fails) {
|
||||||
EXPECT_EQ(1, 2)
|
EXPECT_EQ(1, 2)
|
||||||
<< "This test fails in order to demonstrate alternative failure messages";
|
<< "This test fails in order to demonstrate alternative failure messages";
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
@ -139,10 +135,10 @@ int main(int argc, char **argv) {
|
||||||
// This is an example of using the UnitTest reflection API to inspect test
|
// This is an example of using the UnitTest reflection API to inspect test
|
||||||
// results. Here we discount failures from the tests we expected to fail.
|
// results. Here we discount failures from the tests we expected to fail.
|
||||||
int unexpectedly_failed_tests = 0;
|
int unexpectedly_failed_tests = 0;
|
||||||
for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
|
for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
|
||||||
const TestCase& test_case = *unit_test.GetTestCase(i);
|
const testing::TestSuite& test_suite = *unit_test.GetTestSuite(i);
|
||||||
for (int j = 0; j < test_case.total_test_count(); ++j) {
|
for (int j = 0; j < test_suite.total_test_count(); ++j) {
|
||||||
const TestInfo& test_info = *test_case.GetTestInfo(j);
|
const TestInfo& test_info = *test_suite.GetTestInfo(j);
|
||||||
// Counts failed tests that were not meant to fail (those without
|
// Counts failed tests that were not meant to fail (those without
|
||||||
// 'Fails' in the name).
|
// 'Fails' in the name).
|
||||||
if (test_info.result()->Failed() &&
|
if (test_info.result()->Failed() &&
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Please Note:
|
||||||
|
|
||||||
|
Files in this directory are no longer supported by the maintainers. They
|
||||||
|
represent mosty historical artifacts and supported by the community only. There
|
||||||
|
is no guarantee whatsoever that these scripts still work.
|
|
@ -52,7 +52,7 @@ EXAMPLES
|
||||||
This tool is experimental. In particular, it assumes that there is no
|
This tool is experimental. In particular, it assumes that there is no
|
||||||
conditional inclusion of Google Test headers. Please report any
|
conditional inclusion of Google Test headers. Please report any
|
||||||
problems to googletestframework@googlegroups.com. You can read
|
problems to googletestframework@googlegroups.com. You can read
|
||||||
http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide for
|
https://github.com/google/googletest/blob/master/googletest/docs/advanced.md for
|
||||||
more information.
|
more information.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ def HeaderPreamble(n):
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
"""// Copyright 2006, Google Inc.
|
"""// Copyright 2006, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -111,14 +111,15 @@ def HeaderPreamble(n):
|
||||||
// '%(command)s'. DO NOT EDIT BY HAND!
|
// '%(command)s'. DO NOT EDIT BY HAND!
|
||||||
//
|
//
|
||||||
// Implements a family of generic predicate assertion macros.
|
// Implements a family of generic predicate assertion macros.
|
||||||
|
// GOOGLETEST_CM0001 DO NOT DELETE
|
||||||
|
|
||||||
|
|
||||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||||
#define 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.
|
#include "gtest/gtest.h"
|
||||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
|
|
||||||
# error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
|
namespace testing {
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
|
|
||||||
|
|
||||||
// This header implements a family of generic predicate assertion
|
// This header implements a family of generic predicate assertion
|
||||||
// macros:
|
// macros:
|
||||||
|
@ -247,8 +248,10 @@ AssertionResult AssertPred%(n)sHelper(const char* pred_text""" % DEFS
|
||||||
|
|
||||||
impl += ' << ") evaluates to false, where"'
|
impl += ' << ") evaluates to false, where"'
|
||||||
|
|
||||||
impl += Iter(n, """
|
impl += Iter(
|
||||||
<< "\\n" << e%s << " evaluates to " << v%s""")
|
n, """
|
||||||
|
<< "\\n" << e%s << " evaluates to " << ::testing::PrintToString(v%s)"""
|
||||||
|
)
|
||||||
|
|
||||||
impl += """;
|
impl += """;
|
||||||
}
|
}
|
||||||
|
@ -295,16 +298,17 @@ def HeaderPostamble():
|
||||||
|
|
||||||
return """
|
return """
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def GenerateFile(path, content):
|
def GenerateFile(path, content):
|
||||||
"""Given a file path and a content string, overwrites it with the
|
"""Given a file path and a content string
|
||||||
given content."""
|
overwrites it with the given content.
|
||||||
|
"""
|
||||||
print 'Updating file %s . . .' % path
|
print 'Updating file %s . . .' % path
|
||||||
|
|
||||||
f = file(path, 'w+')
|
f = file(path, 'w+')
|
||||||
print >>f, content,
|
print >>f, content,
|
||||||
f.close()
|
f.close()
|
||||||
|
@ -314,8 +318,8 @@ def GenerateFile(path, content):
|
||||||
|
|
||||||
def GenerateHeader(n):
|
def GenerateHeader(n):
|
||||||
"""Given the maximum arity n, updates the header file that implements
|
"""Given the maximum arity n, updates the header file that implements
|
||||||
the predicate assertions."""
|
the predicate assertions.
|
||||||
|
"""
|
||||||
GenerateFile(HEADER,
|
GenerateFile(HEADER,
|
||||||
HeaderPreamble(n)
|
HeaderPreamble(n)
|
||||||
+ ''.join([ImplementationForArity(i) for i in OneTo(n)])
|
+ ''.join([ImplementationForArity(i) for i in OneTo(n)])
|
||||||
|
@ -333,7 +337,7 @@ def UnitTestPreamble():
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
"""// Copyright 2006, Google Inc.
|
"""// Copyright 2006, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -427,7 +431,7 @@ def TestsForArity(n):
|
||||||
}
|
}
|
||||||
|
|
||||||
tests = (
|
tests = (
|
||||||
"""// Sample functions/functors for testing %(arity)s predicate assertions.
|
"""// Sample functions/functors for testing %(arity)s predicate assertions.
|
||||||
|
|
||||||
// A %(arity)s predicate function.
|
// A %(arity)s predicate function.
|
||||||
template <%(types)s>
|
template <%(types)s>
|
||||||
|
@ -435,9 +439,8 @@ bool PredFunction%(n)s(%(tvs)s) {
|
||||||
return %(v_sum)s > 0;
|
return %(v_sum)s > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following two functions are needed to circumvent a bug in
|
// The following two functions are needed because a compiler doesn't have
|
||||||
// gcc 2.95.3, which sometimes has problem with the above template
|
// a context yet to know which template function must be instantiated.
|
||||||
// function.
|
|
||||||
bool PredFunction%(n)sInt(%(int_vs)s) {
|
bool PredFunction%(n)sInt(%(int_vs)s) {
|
||||||
return %(v_sum)s > 0;
|
return %(v_sum)s > 0;
|
||||||
}
|
}
|
||||||
|
@ -510,7 +513,7 @@ struct PredFormatFunctor%(n)s {
|
||||||
|
|
||||||
class Predicate%(n)sTest : public testing::Test {
|
class Predicate%(n)sTest : public testing::Test {
|
||||||
protected:
|
protected:
|
||||||
virtual void SetUp() {
|
void SetUp() override {
|
||||||
expected_to_finish_ = true;
|
expected_to_finish_ = true;
|
||||||
finished_ = false;""" % DEFS
|
finished_ = false;""" % DEFS
|
||||||
|
|
||||||
|
@ -520,7 +523,7 @@ class Predicate%(n)sTest : public testing::Test {
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tests += """
|
tests += """
|
||||||
virtual void TearDown() {
|
void TearDown() override {
|
||||||
// Verifies that each of the predicate's arguments was evaluated
|
// Verifies that each of the predicate's arguments was evaluated
|
||||||
// exactly once."""
|
// exactly once."""
|
||||||
|
|
||||||
|
@ -540,10 +543,10 @@ class Predicate%(n)sTest : public testing::Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// true iff the test function is expected to run to finish.
|
// true if and only if the test function is expected to run to finish.
|
||||||
static bool expected_to_finish_;
|
static bool expected_to_finish_;
|
||||||
|
|
||||||
// true iff the test function did run to finish.
|
// true if and only if the test function did run to finish.
|
||||||
static bool finished_;
|
static bool finished_;
|
||||||
""" % DEFS
|
""" % DEFS
|
||||||
|
|
||||||
|
@ -572,12 +575,12 @@ typedef Predicate%(n)sTest ASSERT_PRED%(n)sTest;
|
||||||
"""Returns the test for a predicate assertion macro.
|
"""Returns the test for a predicate assertion macro.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
use_format: true iff the assertion is a *_PRED_FORMAT*.
|
use_format: true if and only if the assertion is a *_PRED_FORMAT*.
|
||||||
use_assert: true iff the assertion is a ASSERT_*.
|
use_assert: true if and only if the assertion is a ASSERT_*.
|
||||||
expect_failure: true iff the assertion is expected to fail.
|
expect_failure: true if and only if the assertion is expected to fail.
|
||||||
use_functor: true iff the first argument of the assertion is
|
use_functor: true if and only if the first argument of the assertion is
|
||||||
a functor (as opposed to a function)
|
a functor (as opposed to a function)
|
||||||
use_user_type: true iff the predicate functor/function takes
|
use_user_type: true if and only if the predicate functor/function takes
|
||||||
argument(s) of a user-defined type.
|
argument(s) of a user-defined type.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -588,7 +591,7 @@ typedef Predicate%(n)sTest ASSERT_PRED%(n)sTest;
|
||||||
|
|
||||||
if use_assert:
|
if use_assert:
|
||||||
assrt = 'ASSERT' # 'assert' is reserved, so we cannot use
|
assrt = 'ASSERT' # 'assert' is reserved, so we cannot use
|
||||||
# that identifier here.
|
# that identifier here.
|
||||||
else:
|
else:
|
||||||
assrt = 'EXPECT'
|
assrt = 'EXPECT'
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ SYNOPSIS
|
||||||
interlinked wiki files. When we release a new version of
|
interlinked wiki files. When we release a new version of
|
||||||
Google Test or Google Mock, we need to branch the wiki files
|
Google Test or Google Mock, we need to branch the wiki files
|
||||||
such that users of a specific version of Google Test/Mock can
|
such that users of a specific version of Google Test/Mock can
|
||||||
look up documenation relevant for that version. This script
|
look up documentation relevant for that version. This script
|
||||||
automates that process by:
|
automates that process by:
|
||||||
|
|
||||||
- branching the current wiki pages (which document the
|
- branching the current wiki pages (which document the
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2010 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
"""Runs program specified in the command line with the substituted PATH.
|
||||||
|
|
||||||
|
This script is needed for to support building under Pulse which is unable
|
||||||
|
to override the existing PATH variable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
SUBST_PATH_ENV_VAR_NAME = "SUBST_PATH"
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if SUBST_PATH_ENV_VAR_NAME in os.environ:
|
||||||
|
os.environ["PATH"] = os.environ[SUBST_PATH_ENV_VAR_NAME]
|
||||||
|
|
||||||
|
exit_code = subprocess.Popen(sys.argv[1:]).wait()
|
||||||
|
|
||||||
|
# exit_code is negative (-signal) if the process has been terminated by
|
||||||
|
# a signal. Returning negative exit code is not portable and so we return
|
||||||
|
# 100 instead.
|
||||||
|
if exit_code < 0:
|
||||||
|
exit_code = 100
|
||||||
|
|
||||||
|
sys.exit(exit_code)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -1,18 +1,33 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#
|
#
|
||||||
# Copyright 2007 Google Inc.
|
# Copyright 2007, Google Inc.
|
||||||
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Redistribution and use in source and binary forms, with or without
|
||||||
# you may not use this file except in compliance with the License.
|
# modification, are permitted provided that the following conditions are
|
||||||
# You may obtain a copy of the License at
|
# met:
|
||||||
#
|
#
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
# * 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.
|
||||||
#
|
#
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
# See the License for the specific language governing permissions and
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
# limitations under the License.
|
# 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.
|
||||||
|
|
||||||
"""Tool for uploading diffs from a version control system to the codereview app.
|
"""Tool for uploading diffs from a version control system to the codereview app.
|
||||||
|
|
||||||
|
@ -242,7 +257,7 @@ class AbstractRpcServer(object):
|
||||||
The authentication process works as follows:
|
The authentication process works as follows:
|
||||||
1) We get a username and password from the user
|
1) We get a username and password from the user
|
||||||
2) We use ClientLogin to obtain an AUTH token for the user
|
2) We use ClientLogin to obtain an AUTH token for the user
|
||||||
(see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
|
(see https://developers.google.com/identity/protocols/AuthForInstalledApps).
|
||||||
3) We pass the auth token to /_ah/login on the server to obtain an
|
3) We pass the auth token to /_ah/login on the server to obtain an
|
||||||
authentication cookie. If login was successful, it tries to redirect
|
authentication cookie. If login was successful, it tries to redirect
|
||||||
us to the URL we provided.
|
us to the URL we provided.
|
||||||
|
@ -506,7 +521,7 @@ def EncodeMultipartFormData(fields, files):
|
||||||
(content_type, body) ready for httplib.HTTP instance.
|
(content_type, body) ready for httplib.HTTP instance.
|
||||||
|
|
||||||
Source:
|
Source:
|
||||||
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
|
https://web.archive.org/web/20160116052001/code.activestate.com/recipes/146306
|
||||||
"""
|
"""
|
||||||
BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
|
BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
|
||||||
CRLF = '\r\n'
|
CRLF = '\r\n'
|
||||||
|
@ -732,7 +747,7 @@ class SubversionVCS(VersionControlSystem):
|
||||||
else:
|
else:
|
||||||
self.rev_start = self.rev_end = None
|
self.rev_start = self.rev_end = None
|
||||||
# Cache output from "svn list -r REVNO dirname".
|
# Cache output from "svn list -r REVNO dirname".
|
||||||
# Keys: dirname, Values: 2-tuple (ouput for start rev and end rev).
|
# Keys: dirname, Values: 2-tuple (output for start rev and end rev).
|
||||||
self.svnls_cache = {}
|
self.svnls_cache = {}
|
||||||
# SVN base URL is required to fetch files deleted in an older revision.
|
# SVN base URL is required to fetch files deleted in an older revision.
|
||||||
# Result is cached to not guess it over and over again in GetBaseFile().
|
# Result is cached to not guess it over and over again in GetBaseFile().
|
||||||
|
@ -807,7 +822,7 @@ class SubversionVCS(VersionControlSystem):
|
||||||
# svn cat translates keywords but svn diff doesn't. As a result of this
|
# svn cat translates keywords but svn diff doesn't. As a result of this
|
||||||
# behavior patching.PatchChunks() fails with a chunk mismatch error.
|
# behavior patching.PatchChunks() fails with a chunk mismatch error.
|
||||||
# This part was originally written by the Review Board development team
|
# This part was originally written by the Review Board development team
|
||||||
# who had the same problem (http://reviews.review-board.org/r/276/).
|
# who had the same problem (https://reviews.reviewboard.org/r/276/).
|
||||||
# Mapping of keywords to known aliases
|
# Mapping of keywords to known aliases
|
||||||
svn_keywords = {
|
svn_keywords = {
|
||||||
# Standard keywords
|
# Standard keywords
|
||||||
|
@ -860,7 +875,7 @@ class SubversionVCS(VersionControlSystem):
|
||||||
status_lines = status.splitlines()
|
status_lines = status.splitlines()
|
||||||
# If file is in a cl, the output will begin with
|
# If file is in a cl, the output will begin with
|
||||||
# "\n--- Changelist 'cl_name':\n". See
|
# "\n--- Changelist 'cl_name':\n". See
|
||||||
# http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt
|
# https://web.archive.org/web/20090918234815/svn.collab.net/repos/svn/trunk/notes/changelist-design.txt
|
||||||
if (len(status_lines) == 3 and
|
if (len(status_lines) == 3 and
|
||||||
not status_lines[0] and
|
not status_lines[0] and
|
||||||
status_lines[1].startswith("--- Changelist")):
|
status_lines[1].startswith("--- Changelist")):
|
||||||
|
|
|
@ -26,10 +26,9 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
//
|
//
|
||||||
// Author: mheule@google.com (Markus Heule)
|
// Google C++ Testing and Mocking Framework (Google Test)
|
||||||
//
|
|
||||||
// Google C++ Testing Framework (Google Test)
|
|
||||||
//
|
//
|
||||||
// Sometimes it's desirable to build Google Test by compiling a single file.
|
// Sometimes it's desirable to build Google Test by compiling a single file.
|
||||||
// This file serves this purpose.
|
// This file serves this purpose.
|
||||||
|
@ -42,6 +41,7 @@
|
||||||
#include "src/gtest.cc"
|
#include "src/gtest.cc"
|
||||||
#include "src/gtest-death-test.cc"
|
#include "src/gtest-death-test.cc"
|
||||||
#include "src/gtest-filepath.cc"
|
#include "src/gtest-filepath.cc"
|
||||||
|
#include "src/gtest-matchers.cc"
|
||||||
#include "src/gtest-port.cc"
|
#include "src/gtest-port.cc"
|
||||||
#include "src/gtest-printers.cc"
|
#include "src/gtest-printers.cc"
|
||||||
#include "src/gtest-test-part.cc"
|
#include "src/gtest-test-part.cc"
|
||||||
|
|
|
@ -26,12 +26,15 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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.
|
// This file implements death tests.
|
||||||
|
|
||||||
#include "gtest/gtest-death-test.h"
|
#include "gtest/gtest-death-test.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "gtest/internal/gtest-port.h"
|
#include "gtest/internal/gtest-port.h"
|
||||||
#include "gtest/internal/custom/gtest.h"
|
#include "gtest/internal/custom/gtest.h"
|
||||||
|
|
||||||
|
@ -62,26 +65,36 @@
|
||||||
# include <spawn.h>
|
# include <spawn.h>
|
||||||
# endif // GTEST_OS_QNX
|
# endif // GTEST_OS_QNX
|
||||||
|
|
||||||
|
# if GTEST_OS_FUCHSIA
|
||||||
|
# include <lib/fdio/fd.h>
|
||||||
|
# include <lib/fdio/io.h>
|
||||||
|
# include <lib/fdio/spawn.h>
|
||||||
|
# include <lib/zx/channel.h>
|
||||||
|
# include <lib/zx/port.h>
|
||||||
|
# include <lib/zx/process.h>
|
||||||
|
# include <lib/zx/socket.h>
|
||||||
|
# include <zircon/processargs.h>
|
||||||
|
# include <zircon/syscalls.h>
|
||||||
|
# include <zircon/syscalls/policy.h>
|
||||||
|
# include <zircon/syscalls/port.h>
|
||||||
|
# endif // GTEST_OS_FUCHSIA
|
||||||
|
|
||||||
#endif // GTEST_HAS_DEATH_TEST
|
#endif // GTEST_HAS_DEATH_TEST
|
||||||
|
|
||||||
#include "gtest/gtest-message.h"
|
#include "gtest/gtest-message.h"
|
||||||
#include "gtest/internal/gtest-string.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 exists to
|
|
||||||
// prevent the accidental inclusion of gtest-internal-inl.h in the
|
|
||||||
// user's code.
|
|
||||||
#define GTEST_IMPLEMENTATION_ 1
|
|
||||||
#include "src/gtest-internal-inl.h"
|
#include "src/gtest-internal-inl.h"
|
||||||
#undef GTEST_IMPLEMENTATION_
|
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
|
||||||
// Constants.
|
// Constants.
|
||||||
|
|
||||||
// The default death test style.
|
// 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_(
|
GTEST_DEFINE_string_(
|
||||||
death_test_style,
|
death_test_style,
|
||||||
|
@ -110,8 +123,8 @@ GTEST_DEFINE_string_(
|
||||||
"Indicates the file, line number, temporal index of "
|
"Indicates the file, line number, temporal index of "
|
||||||
"the single death test to run, and a file descriptor to "
|
"the single death test to run, and a file descriptor to "
|
||||||
"which a success code may be sent, all separated by "
|
"which a success code may be sent, all separated by "
|
||||||
"the '|' characters. This flag is specified if and only if the current "
|
"the '|' characters. This flag is specified if and only if the "
|
||||||
"process is a sub-process launched for running a thread-safe "
|
"current process is a sub-process launched for running a thread-safe "
|
||||||
"death test. FOR INTERNAL USE ONLY.");
|
"death test. FOR INTERNAL USE ONLY.");
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
@ -121,7 +134,7 @@ namespace internal {
|
||||||
|
|
||||||
// Valid only for fast death tests. Indicates the code is running in the
|
// Valid only for fast death tests. Indicates the code is running in the
|
||||||
// child process of a fast style death test.
|
// child process of a fast style death test.
|
||||||
# if !GTEST_OS_WINDOWS
|
# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
|
||||||
static bool g_in_fast_death_test_child = false;
|
static bool g_in_fast_death_test_child = false;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
@ -131,10 +144,10 @@ static bool g_in_fast_death_test_child = false;
|
||||||
// tests. IMPORTANT: This is an internal utility. Using it may break the
|
// tests. IMPORTANT: This is an internal utility. Using it may break the
|
||||||
// implementation of death tests. User code MUST NOT use it.
|
// implementation of death tests. User code MUST NOT use it.
|
||||||
bool InDeathTestChild() {
|
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
|
// On Windows and Fuchsia, death tests are thread-safe regardless of the value
|
||||||
// death_test_style flag.
|
// of the death_test_style flag.
|
||||||
return !GTEST_FLAG(internal_run_death_test).empty();
|
return !GTEST_FLAG(internal_run_death_test).empty();
|
||||||
|
|
||||||
# else
|
# else
|
||||||
|
@ -154,7 +167,7 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
|
||||||
|
|
||||||
// ExitedWithCode function-call operator.
|
// ExitedWithCode function-call operator.
|
||||||
bool ExitedWithCode::operator()(int exit_status) const {
|
bool ExitedWithCode::operator()(int exit_status) const {
|
||||||
# if GTEST_OS_WINDOWS
|
# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
|
||||||
|
|
||||||
return exit_status == exit_code_;
|
return exit_status == exit_code_;
|
||||||
|
|
||||||
|
@ -162,10 +175,10 @@ bool ExitedWithCode::operator()(int exit_status) const {
|
||||||
|
|
||||||
return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
|
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 constructor.
|
||||||
KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
|
KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
|
||||||
}
|
}
|
||||||
|
@ -182,7 +195,7 @@ bool KilledBySignal::operator()(int exit_status) const {
|
||||||
# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
|
# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
|
||||||
return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
|
return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
|
||||||
}
|
}
|
||||||
# endif // !GTEST_OS_WINDOWS
|
# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
@ -193,7 +206,7 @@ namespace internal {
|
||||||
static std::string ExitSummary(int exit_code) {
|
static std::string ExitSummary(int exit_code) {
|
||||||
Message m;
|
Message m;
|
||||||
|
|
||||||
# if GTEST_OS_WINDOWS
|
# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
|
||||||
|
|
||||||
m << "Exited with exit status " << exit_code;
|
m << "Exited with exit status " << exit_code;
|
||||||
|
|
||||||
|
@ -209,7 +222,7 @@ static std::string ExitSummary(int exit_code) {
|
||||||
m << " (core dumped)";
|
m << " (core dumped)";
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
# endif // GTEST_OS_WINDOWS
|
# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
|
||||||
|
|
||||||
return m.GetString();
|
return m.GetString();
|
||||||
}
|
}
|
||||||
|
@ -220,7 +233,7 @@ bool ExitedUnsuccessfully(int exit_status) {
|
||||||
return !ExitedWithCode(0)(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
|
// Generates a textual failure message when a death test finds more than
|
||||||
// one thread running, or cannot determine the number of threads, prior
|
// one thread running, or cannot determine the number of threads, prior
|
||||||
// to executing the given statement. It is the responsibility of the
|
// to executing the given statement. It is the responsibility of the
|
||||||
|
@ -229,13 +242,19 @@ static std::string DeathTestThreadWarning(size_t thread_count) {
|
||||||
Message msg;
|
Message msg;
|
||||||
msg << "Death tests use fork(), which is unsafe particularly"
|
msg << "Death tests use fork(), which is unsafe particularly"
|
||||||
<< " in a threaded context. For this test, " << GTEST_NAME_ << " ";
|
<< " 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.";
|
msg << "couldn't detect the number of threads.";
|
||||||
else
|
} else {
|
||||||
msg << "detected " << thread_count << " threads.";
|
msg << "detected " << thread_count << " threads.";
|
||||||
|
}
|
||||||
|
msg << " See "
|
||||||
|
"https://github.com/google/googletest/blob/master/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();
|
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.
|
// Flag characters for reporting a death test that did not die.
|
||||||
static const char kDeathTestLived = 'L';
|
static const char kDeathTestLived = 'L';
|
||||||
|
@ -243,6 +262,13 @@ static const char kDeathTestReturned = 'R';
|
||||||
static const char kDeathTestThrew = 'T';
|
static const char kDeathTestThrew = 'T';
|
||||||
static const char kDeathTestInternalError = 'I';
|
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
|
// An enumeration describing all of the possible ways that a death test can
|
||||||
// conclude. DIED means that the process died while executing the test
|
// conclude. DIED means that the process died while executing the test
|
||||||
// code; LIVED means that process lived beyond the end of the test code;
|
// code; LIVED means that process lived beyond the end of the test code;
|
||||||
|
@ -250,8 +276,6 @@ static const char kDeathTestInternalError = 'I';
|
||||||
// statement, which is not allowed; THREW means that the test statement
|
// statement, which is not allowed; THREW means that the test statement
|
||||||
// returned control by throwing an exception. IN_PROGRESS means the test
|
// returned control by throwing an exception. IN_PROGRESS means the test
|
||||||
// has not yet concluded.
|
// 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 };
|
enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
|
||||||
|
|
||||||
// Routine for aborting the program which is safe to call from an
|
// Routine for aborting the program which is safe to call from an
|
||||||
|
@ -259,13 +283,13 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
|
||||||
// message is propagated back to the parent process. Otherwise, the
|
// message is propagated back to the parent process. Otherwise, the
|
||||||
// message is simply printed to stderr. In either case, the program
|
// message is simply printed to stderr. In either case, the program
|
||||||
// then exits with status 1.
|
// 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
|
// 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
|
// death test child process, which operates on a very small stack. Use
|
||||||
// the heap for any additional non-minuscule memory requirements.
|
// the heap for any additional non-minuscule memory requirements.
|
||||||
const InternalRunDeathTestFlag* const flag =
|
const InternalRunDeathTestFlag* const flag =
|
||||||
GetUnitTestImpl()->internal_run_death_test_flag();
|
GetUnitTestImpl()->internal_run_death_test_flag();
|
||||||
if (flag != NULL) {
|
if (flag != nullptr) {
|
||||||
FILE* parent = posix::FDOpen(flag->write_fd(), "w");
|
FILE* parent = posix::FDOpen(flag->write_fd(), "w");
|
||||||
fputc(kDeathTestInternalError, parent);
|
fputc(kDeathTestInternalError, parent);
|
||||||
fprintf(parent, "%s", message.c_str());
|
fprintf(parent, "%s", message.c_str());
|
||||||
|
@ -345,7 +369,7 @@ static void FailFromInternalError(int fd) {
|
||||||
// for the current test.
|
// for the current test.
|
||||||
DeathTest::DeathTest() {
|
DeathTest::DeathTest() {
|
||||||
TestInfo* const info = GetUnitTestImpl()->current_test_info();
|
TestInfo* const info = GetUnitTestImpl()->current_test_info();
|
||||||
if (info == NULL) {
|
if (info == nullptr) {
|
||||||
DeathTestAbort("Cannot run a death test outside of a TEST or "
|
DeathTestAbort("Cannot run a death test outside of a TEST or "
|
||||||
"TEST_F construct");
|
"TEST_F construct");
|
||||||
}
|
}
|
||||||
|
@ -353,10 +377,11 @@ DeathTest::DeathTest() {
|
||||||
|
|
||||||
// Creates and returns a death test by dispatching to the current
|
// Creates and returns a death test by dispatching to the current
|
||||||
// death test factory.
|
// death test factory.
|
||||||
bool DeathTest::Create(const char* statement, const RE* regex,
|
bool DeathTest::Create(const char* statement,
|
||||||
const char* file, int line, DeathTest** test) {
|
Matcher<const std::string&> matcher, const char* file,
|
||||||
|
int line, DeathTest** test) {
|
||||||
return GetUnitTestImpl()->death_test_factory()->Create(
|
return GetUnitTestImpl()->death_test_factory()->Create(
|
||||||
statement, regex, file, line, test);
|
statement, std::move(matcher), file, line, test);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DeathTest::LastMessage() {
|
const char* DeathTest::LastMessage() {
|
||||||
|
@ -372,9 +397,9 @@ std::string DeathTest::last_death_test_message_;
|
||||||
// Provides cross platform implementation for some death functionality.
|
// Provides cross platform implementation for some death functionality.
|
||||||
class DeathTestImpl : public DeathTest {
|
class DeathTestImpl : public DeathTest {
|
||||||
protected:
|
protected:
|
||||||
DeathTestImpl(const char* a_statement, const RE* a_regex)
|
DeathTestImpl(const char* a_statement, Matcher<const std::string&> matcher)
|
||||||
: statement_(a_statement),
|
: statement_(a_statement),
|
||||||
regex_(a_regex),
|
matcher_(std::move(matcher)),
|
||||||
spawned_(false),
|
spawned_(false),
|
||||||
status_(-1),
|
status_(-1),
|
||||||
outcome_(IN_PROGRESS),
|
outcome_(IN_PROGRESS),
|
||||||
|
@ -382,13 +407,12 @@ class DeathTestImpl : public DeathTest {
|
||||||
write_fd_(-1) {}
|
write_fd_(-1) {}
|
||||||
|
|
||||||
// read_fd_ is expected to be closed and cleared by a derived class.
|
// 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);
|
void Abort(AbortReason reason) override;
|
||||||
virtual bool Passed(bool status_ok);
|
bool Passed(bool status_ok) override;
|
||||||
|
|
||||||
const char* statement() const { return statement_; }
|
const char* statement() const { return statement_; }
|
||||||
const RE* regex() const { return regex_; }
|
|
||||||
bool spawned() const { return spawned_; }
|
bool spawned() const { return spawned_; }
|
||||||
void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
|
void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
|
||||||
int status() const { return status_; }
|
int status() const { return status_; }
|
||||||
|
@ -406,13 +430,15 @@ class DeathTestImpl : public DeathTest {
|
||||||
// case of unexpected codes.
|
// case of unexpected codes.
|
||||||
void ReadAndInterpretStatusByte();
|
void ReadAndInterpretStatusByte();
|
||||||
|
|
||||||
|
// Returns stderr output from the child process.
|
||||||
|
virtual std::string GetErrorLogs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The textual content of the code this object is testing. This class
|
// The textual content of the code this object is testing. This class
|
||||||
// doesn't own this string and should not attempt to delete it.
|
// doesn't own this string and should not attempt to delete it.
|
||||||
const char* const statement_;
|
const char* const statement_;
|
||||||
// The regular expression which test output must match. DeathTestImpl
|
// A matcher that's expected to match the stderr output by the child process.
|
||||||
// doesn't own this object and should not attempt to delete it.
|
Matcher<const std::string&> matcher_;
|
||||||
const RE* const regex_;
|
|
||||||
// True if the death test child process has been successfully spawned.
|
// True if the death test child process has been successfully spawned.
|
||||||
bool spawned_;
|
bool spawned_;
|
||||||
// The exit status of the child process.
|
// The exit status of the child process.
|
||||||
|
@ -474,6 +500,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() {
|
||||||
set_read_fd(-1);
|
set_read_fd(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string DeathTestImpl::GetErrorLogs() {
|
||||||
|
return GetCapturedStderr();
|
||||||
|
}
|
||||||
|
|
||||||
// Signals that the death test code which should have exited, didn't.
|
// Signals that the death test code which should have exited, didn't.
|
||||||
// Should be called only in a death test child process.
|
// Should be called only in a death test child process.
|
||||||
// Writes a status byte to the child's status file descriptor, then
|
// Writes a status byte to the child's status file descriptor, then
|
||||||
|
@ -527,22 +557,21 @@ static ::std::string FormatDeathTestOutput(const ::std::string& output) {
|
||||||
// in the format specified by wait(2). On Windows, this is the
|
// in the format specified by wait(2). On Windows, this is the
|
||||||
// value supplied to the ExitProcess() API or a numeric code
|
// value supplied to the ExitProcess() API or a numeric code
|
||||||
// of the exception that terminated the program.
|
// of the exception that terminated the program.
|
||||||
// regex: A regular expression object to be applied to
|
// matcher_: A matcher that's expected to match the stderr output by the child
|
||||||
// the test's captured standard error output; the death test
|
// process.
|
||||||
// fails if it does not match.
|
|
||||||
//
|
//
|
||||||
// Argument:
|
// Argument:
|
||||||
// status_ok: true if exit_status is acceptable in the context of
|
// status_ok: true if exit_status is acceptable in the context of
|
||||||
// this particular death test, which fails if it is false
|
// this particular death test, which fails if it is false
|
||||||
//
|
//
|
||||||
// Returns true iff all of the above conditions are met. Otherwise, the
|
// Returns true if and only if all of the above conditions are met. Otherwise,
|
||||||
// first failing condition, in the order given above, is the one that is
|
// the first failing condition, in the order given above, is the one that is
|
||||||
// reported. Also sets the last death test message string.
|
// reported. Also sets the last death test message string.
|
||||||
bool DeathTestImpl::Passed(bool status_ok) {
|
bool DeathTestImpl::Passed(bool status_ok) {
|
||||||
if (!spawned())
|
if (!spawned())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const std::string error_message = GetCapturedStderr();
|
const std::string error_message = GetErrorLogs();
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
Message buffer;
|
Message buffer;
|
||||||
|
@ -563,13 +592,15 @@ bool DeathTestImpl::Passed(bool status_ok) {
|
||||||
break;
|
break;
|
||||||
case DIED:
|
case DIED:
|
||||||
if (status_ok) {
|
if (status_ok) {
|
||||||
const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
|
if (matcher_.Matches(error_message)) {
|
||||||
if (matched) {
|
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
|
std::ostringstream stream;
|
||||||
|
matcher_.DescribeTo(&stream);
|
||||||
buffer << " Result: died but not with expected error.\n"
|
buffer << " Result: died but not with expected error.\n"
|
||||||
<< " Expected: " << regex()->pattern() << "\n"
|
<< " Expected: " << stream.str() << "\n"
|
||||||
<< "Actual msg:\n" << FormatDeathTestOutput(error_message);
|
<< "Actual msg:\n"
|
||||||
|
<< FormatDeathTestOutput(error_message);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buffer << " Result: died but not with expected exit code:\n"
|
buffer << " Result: died but not with expected exit code:\n"
|
||||||
|
@ -618,11 +649,11 @@ bool DeathTestImpl::Passed(bool status_ok) {
|
||||||
//
|
//
|
||||||
class WindowsDeathTest : public DeathTestImpl {
|
class WindowsDeathTest : public DeathTestImpl {
|
||||||
public:
|
public:
|
||||||
WindowsDeathTest(const char* a_statement,
|
WindowsDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
|
||||||
const RE* a_regex,
|
const char* file, int line)
|
||||||
const char* file,
|
: DeathTestImpl(a_statement, std::move(matcher)),
|
||||||
int line)
|
file_(file),
|
||||||
: DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
|
line_(line) {}
|
||||||
|
|
||||||
// All of these virtual functions are inherited from DeathTest.
|
// All of these virtual functions are inherited from DeathTest.
|
||||||
virtual int Wait();
|
virtual int Wait();
|
||||||
|
@ -699,7 +730,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
|
||||||
const TestInfo* const info = impl->current_test_info();
|
const TestInfo* const info = impl->current_test_info();
|
||||||
const int death_test_index = info->result()->death_test_count();
|
const int death_test_index = info->result()->death_test_count();
|
||||||
|
|
||||||
if (flag != NULL) {
|
if (flag != nullptr) {
|
||||||
// ParseInternalRunDeathTestFlag() has performed all the necessary
|
// ParseInternalRunDeathTestFlag() has performed all the necessary
|
||||||
// processing.
|
// processing.
|
||||||
set_write_fd(flag->write_fd());
|
set_write_fd(flag->write_fd());
|
||||||
|
@ -708,8 +739,8 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
|
||||||
|
|
||||||
// WindowsDeathTest uses an anonymous pipe to communicate results of
|
// WindowsDeathTest uses an anonymous pipe to communicate results of
|
||||||
// a death test.
|
// a death test.
|
||||||
SECURITY_ATTRIBUTES handles_are_inheritable = {
|
SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES),
|
||||||
sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
|
nullptr, TRUE};
|
||||||
HANDLE read_handle, write_handle;
|
HANDLE read_handle, write_handle;
|
||||||
GTEST_DEATH_TEST_CHECK_(
|
GTEST_DEATH_TEST_CHECK_(
|
||||||
::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
|
::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
|
||||||
|
@ -720,13 +751,13 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
|
||||||
write_handle_.Reset(write_handle);
|
write_handle_.Reset(write_handle);
|
||||||
event_handle_.Reset(::CreateEvent(
|
event_handle_.Reset(::CreateEvent(
|
||||||
&handles_are_inheritable,
|
&handles_are_inheritable,
|
||||||
TRUE, // The event will automatically reset to non-signaled state.
|
TRUE, // The event will automatically reset to non-signaled state.
|
||||||
FALSE, // The initial state is non-signalled.
|
FALSE, // The initial state is non-signalled.
|
||||||
NULL)); // The even is unnamed.
|
nullptr)); // The even is unnamed.
|
||||||
GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
|
GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr);
|
||||||
const std::string filter_flag =
|
const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
|
||||||
std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" +
|
kFilterFlag + "=" + info->test_suite_name() +
|
||||||
info->test_case_name() + "." + info->name();
|
"." + info->name();
|
||||||
const std::string internal_flag =
|
const std::string internal_flag =
|
||||||
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
|
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
|
||||||
"=" + file_ + "|" + StreamableToString(line_) + "|" +
|
"=" + file_ + "|" + StreamableToString(line_) + "|" +
|
||||||
|
@ -739,10 +770,9 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
|
||||||
"|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
|
"|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
|
||||||
|
|
||||||
char executable_path[_MAX_PATH + 1]; // NOLINT
|
char executable_path[_MAX_PATH + 1]; // NOLINT
|
||||||
GTEST_DEATH_TEST_CHECK_(
|
GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr,
|
||||||
_MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
|
executable_path,
|
||||||
executable_path,
|
_MAX_PATH));
|
||||||
_MAX_PATH));
|
|
||||||
|
|
||||||
std::string command_line =
|
std::string command_line =
|
||||||
std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
|
std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
|
||||||
|
@ -763,33 +793,288 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
|
||||||
startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
|
startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
|
||||||
PROCESS_INFORMATION process_info;
|
PROCESS_INFORMATION process_info;
|
||||||
GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
|
GTEST_DEATH_TEST_CHECK_(
|
||||||
executable_path,
|
::CreateProcessA(
|
||||||
const_cast<char*>(command_line.c_str()),
|
executable_path, const_cast<char*>(command_line.c_str()),
|
||||||
NULL, // Retuned process handle is not inheritable.
|
nullptr, // Retuned process handle is not inheritable.
|
||||||
NULL, // Retuned thread handle is not inheritable.
|
nullptr, // Retuned thread handle is not inheritable.
|
||||||
TRUE, // Child inherits all inheritable handles (for write_handle_).
|
TRUE, // Child inherits all inheritable handles (for write_handle_).
|
||||||
0x0, // Default creation flags.
|
0x0, // Default creation flags.
|
||||||
NULL, // Inherit the parent's environment.
|
nullptr, // Inherit the parent's environment.
|
||||||
UnitTest::GetInstance()->original_working_dir(),
|
UnitTest::GetInstance()->original_working_dir(), &startup_info,
|
||||||
&startup_info,
|
&process_info) != FALSE);
|
||||||
&process_info) != FALSE);
|
|
||||||
child_handle_.Reset(process_info.hProcess);
|
child_handle_.Reset(process_info.hProcess);
|
||||||
::CloseHandle(process_info.hThread);
|
::CloseHandle(process_info.hThread);
|
||||||
set_spawned(true);
|
set_spawned(true);
|
||||||
return OVERSEE_TEST;
|
return OVERSEE_TEST;
|
||||||
}
|
}
|
||||||
# else // We are not on Windows.
|
|
||||||
|
# elif GTEST_OS_FUCHSIA
|
||||||
|
|
||||||
|
class FuchsiaDeathTest : public DeathTestImpl {
|
||||||
|
public:
|
||||||
|
FuchsiaDeathTest(const char* a_statement, Matcher<const std::string&> 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<char*>::iterator i = args_.begin(); i != args_.end();
|
||||||
|
++i) {
|
||||||
|
free(*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void AddArgument(const char* argument) {
|
||||||
|
args_.insert(args_.end() - 1, posix::StrDup(argument));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Str>
|
||||||
|
void AddArguments(const ::std::vector<Str>& arguments) {
|
||||||
|
for (typename ::std::vector<Str>::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 static_cast<int>(args_.size()) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<char*> 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, 0);
|
||||||
|
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, 0);
|
||||||
|
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, 0);
|
||||||
|
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, 0);
|
||||||
|
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.flags & ZX_INFO_PROCESS_FLAG_EXITED);
|
||||||
|
set_status(static_cast<int>(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
|
// ForkingDeathTest provides implementations for most of the abstract
|
||||||
// methods of the DeathTest interface. Only the AssumeRole method is
|
// methods of the DeathTest interface. Only the AssumeRole method is
|
||||||
// left undefined.
|
// left undefined.
|
||||||
class ForkingDeathTest : public DeathTestImpl {
|
class ForkingDeathTest : public DeathTestImpl {
|
||||||
public:
|
public:
|
||||||
ForkingDeathTest(const char* statement, const RE* regex);
|
ForkingDeathTest(const char* statement, Matcher<const std::string&> matcher);
|
||||||
|
|
||||||
// All of these virtual functions are inherited from DeathTest.
|
// All of these virtual functions are inherited from DeathTest.
|
||||||
virtual int Wait();
|
int Wait() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
|
void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
|
||||||
|
@ -800,9 +1085,9 @@ class ForkingDeathTest : public DeathTestImpl {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructs a ForkingDeathTest.
|
// Constructs a ForkingDeathTest.
|
||||||
ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
|
ForkingDeathTest::ForkingDeathTest(const char* a_statement,
|
||||||
: DeathTestImpl(a_statement, a_regex),
|
Matcher<const std::string&> matcher)
|
||||||
child_pid_(-1) {}
|
: DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {}
|
||||||
|
|
||||||
// Waits for the child in a death test to exit, returning its exit
|
// 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
|
// status, or 0 if no child process exists. As a side effect, sets the
|
||||||
|
@ -823,9 +1108,9 @@ int ForkingDeathTest::Wait() {
|
||||||
// in the child process.
|
// in the child process.
|
||||||
class NoExecDeathTest : public ForkingDeathTest {
|
class NoExecDeathTest : public ForkingDeathTest {
|
||||||
public:
|
public:
|
||||||
NoExecDeathTest(const char* a_statement, const RE* a_regex) :
|
NoExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher)
|
||||||
ForkingDeathTest(a_statement, a_regex) { }
|
: ForkingDeathTest(a_statement, std::move(matcher)) {}
|
||||||
virtual TestRole AssumeRole();
|
TestRole AssumeRole() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The AssumeRole process for a fork-and-run death test. It implements a
|
// The AssumeRole process for a fork-and-run death test. It implements a
|
||||||
|
@ -878,16 +1163,18 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
|
||||||
// only this specific death test to be run.
|
// only this specific death test to be run.
|
||||||
class ExecDeathTest : public ForkingDeathTest {
|
class ExecDeathTest : public ForkingDeathTest {
|
||||||
public:
|
public:
|
||||||
ExecDeathTest(const char* a_statement, const RE* a_regex,
|
ExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
|
||||||
const char* file, int line) :
|
const char* file, int line)
|
||||||
ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
|
: ForkingDeathTest(a_statement, std::move(matcher)),
|
||||||
virtual TestRole AssumeRole();
|
file_(file),
|
||||||
|
line_(line) {}
|
||||||
|
TestRole AssumeRole() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ::std::vector<testing::internal::string>
|
static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() {
|
||||||
GetArgvsForDeathTestChildProcess() {
|
::std::vector<std::string> args = GetInjectableArgvs();
|
||||||
::std::vector<testing::internal::string> args = GetInjectableArgvs();
|
|
||||||
# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
|
# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
|
||||||
::std::vector<testing::internal::string> extra_args =
|
::std::vector<std::string> extra_args =
|
||||||
GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_();
|
GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_();
|
||||||
args.insert(args.end(), extra_args.begin(), extra_args.end());
|
args.insert(args.end(), extra_args.begin(), extra_args.end());
|
||||||
# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
|
# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
|
||||||
|
@ -902,9 +1189,7 @@ class ExecDeathTest : public ForkingDeathTest {
|
||||||
// Utility class for accumulating command-line arguments.
|
// Utility class for accumulating command-line arguments.
|
||||||
class Arguments {
|
class Arguments {
|
||||||
public:
|
public:
|
||||||
Arguments() {
|
Arguments() { args_.push_back(nullptr); }
|
||||||
args_.push_back(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Arguments() {
|
~Arguments() {
|
||||||
for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
|
for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
|
||||||
|
@ -939,21 +1224,9 @@ struct ExecDeathTestArgs {
|
||||||
int close_fd; // File descriptor to close; the read end of a pipe
|
int close_fd; // File descriptor to close; the read end of a pipe
|
||||||
};
|
};
|
||||||
|
|
||||||
# if GTEST_OS_MAC
|
# if GTEST_OS_QNX
|
||||||
inline char** GetEnviron() {
|
|
||||||
// When Google Test is built as a framework on MacOS X, the environ variable
|
|
||||||
// is unavailable. Apple's documentation (man environ) recommends using
|
|
||||||
// _NSGetEnviron() instead.
|
|
||||||
return *_NSGetEnviron();
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
// Some POSIX platforms expect you to declare environ. extern "C" makes
|
|
||||||
// it reside in the global namespace.
|
|
||||||
extern "C" char** environ;
|
extern "C" char** environ;
|
||||||
inline char** GetEnviron() { return environ; }
|
# else // GTEST_OS_QNX
|
||||||
# endif // GTEST_OS_MAC
|
|
||||||
|
|
||||||
# if !GTEST_OS_QNX
|
|
||||||
// The main function for a threadsafe-style death test child process.
|
// The main function for a threadsafe-style death test child process.
|
||||||
// This function is called in a clone()-ed process and thus must avoid
|
// This function is called in a clone()-ed process and thus must avoid
|
||||||
// any potentially unsafe operations like malloc or libc functions.
|
// any potentially unsafe operations like malloc or libc functions.
|
||||||
|
@ -973,19 +1246,20 @@ static int ExecDeathTestChildMain(void* child_arg) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can safely call execve() as it's a direct system call. We
|
// We can safely call execv() as it's almost a direct system call. We
|
||||||
// cannot use execvp() as it's a libc function and thus potentially
|
// cannot use execvp() as it's a libc function and thus potentially
|
||||||
// unsafe. Since execve() doesn't search the PATH, the user must
|
// unsafe. Since execv() doesn't search the PATH, the user must
|
||||||
// invoke the test program via a valid path that contains at least
|
// invoke the test program via a valid path that contains at least
|
||||||
// one path separator.
|
// one path separator.
|
||||||
execve(args->argv[0], args->argv, GetEnviron());
|
execv(args->argv[0], args->argv);
|
||||||
DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " +
|
DeathTestAbort(std::string("execv(") + args->argv[0] + ", ...) in " +
|
||||||
original_dir + " failed: " +
|
original_dir + " failed: " +
|
||||||
GetLastErrnoDescription());
|
GetLastErrnoDescription());
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
# endif // !GTEST_OS_QNX
|
# endif // GTEST_OS_QNX
|
||||||
|
|
||||||
|
# if GTEST_HAS_CLONE
|
||||||
// Two utility routines that together determine the direction the stack
|
// Two utility routines that together determine the direction the stack
|
||||||
// grows.
|
// grows.
|
||||||
// This could be accomplished more elegantly by a single recursive
|
// This could be accomplished more elegantly by a single recursive
|
||||||
|
@ -995,20 +1269,31 @@ static int ExecDeathTestChildMain(void* child_arg) {
|
||||||
// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
|
// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
|
||||||
// StackLowerThanAddress into StackGrowsDown, which then doesn't give
|
// StackLowerThanAddress into StackGrowsDown, which then doesn't give
|
||||||
// correct answer.
|
// correct answer.
|
||||||
void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
|
static void StackLowerThanAddress(const void* ptr,
|
||||||
void StackLowerThanAddress(const void* ptr, bool* result) {
|
bool* result) GTEST_NO_INLINE_;
|
||||||
int dummy;
|
// Make sure sanitizers do not tamper with the stack here.
|
||||||
*result = (&dummy < ptr);
|
// Ideally, we want to use `__builtin_frame_address` instead of a local variable
|
||||||
|
// address with sanitizer disabled, but it does not work when the
|
||||||
|
// compiler optimizes the stack frame out, which happens on PowerPC targets.
|
||||||
|
// HWAddressSanitizer add a random tag to the MSB of the local variable address,
|
||||||
|
// making comparison result unpredictable.
|
||||||
|
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||||
|
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
|
||||||
|
static void StackLowerThanAddress(const void* ptr, bool* result) {
|
||||||
|
int dummy = 0;
|
||||||
|
*result = std::less<const void*>()(&dummy, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure AddressSanitizer does not tamper with the stack here.
|
// Make sure AddressSanitizer does not tamper with the stack here.
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||||
bool StackGrowsDown() {
|
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
|
||||||
int dummy;
|
static bool StackGrowsDown() {
|
||||||
|
int dummy = 0;
|
||||||
bool result;
|
bool result;
|
||||||
StackLowerThanAddress(&dummy, &result);
|
StackLowerThanAddress(&dummy, &result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
# endif // GTEST_HAS_CLONE
|
||||||
|
|
||||||
// Spawns a child process with the same executable as the current process in
|
// 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
|
// a thread-safe manner and instructs it to run the death test. The
|
||||||
|
@ -1046,7 +1331,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
|
||||||
fd_flags | FD_CLOEXEC));
|
fd_flags | FD_CLOEXEC));
|
||||||
struct inheritance inherit = {0};
|
struct inheritance inherit = {0};
|
||||||
// spawn is a system call.
|
// 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, environ);
|
||||||
// Restores the current working directory.
|
// Restores the current working directory.
|
||||||
GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
|
GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
|
||||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
|
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
|
||||||
|
@ -1070,9 +1355,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
|
||||||
|
|
||||||
if (!use_fork) {
|
if (!use_fork) {
|
||||||
static const bool stack_grows_down = StackGrowsDown();
|
static const bool stack_grows_down = StackGrowsDown();
|
||||||
const size_t stack_size = getpagesize();
|
const auto stack_size = static_cast<size_t>(getpagesize() * 2);
|
||||||
// MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
|
// 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);
|
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||||
GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
|
GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
|
||||||
|
|
||||||
|
@ -1086,8 +1371,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
|
||||||
void* const stack_top =
|
void* const stack_top =
|
||||||
static_cast<char*>(stack) +
|
static_cast<char*>(stack) +
|
||||||
(stack_grows_down ? stack_size - kMaxStackAlignment : 0);
|
(stack_grows_down ? stack_size - kMaxStackAlignment : 0);
|
||||||
GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment &&
|
GTEST_DEATH_TEST_CHECK_(
|
||||||
reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0);
|
static_cast<size_t>(stack_size) > kMaxStackAlignment &&
|
||||||
|
reinterpret_cast<uintptr_t>(stack_top) % kMaxStackAlignment == 0);
|
||||||
|
|
||||||
child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
|
child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
|
||||||
|
|
||||||
|
@ -1104,7 +1390,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
|
||||||
# endif // GTEST_OS_QNX
|
# endif // GTEST_OS_QNX
|
||||||
# if GTEST_OS_LINUX
|
# if GTEST_OS_LINUX
|
||||||
GTEST_DEATH_TEST_CHECK_SYSCALL_(
|
GTEST_DEATH_TEST_CHECK_SYSCALL_(
|
||||||
sigaction(SIGPROF, &saved_sigprof_action, NULL));
|
sigaction(SIGPROF, &saved_sigprof_action, nullptr));
|
||||||
# endif // GTEST_OS_LINUX
|
# endif // GTEST_OS_LINUX
|
||||||
|
|
||||||
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
|
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
|
||||||
|
@ -1122,7 +1408,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
|
||||||
const TestInfo* const info = impl->current_test_info();
|
const TestInfo* const info = impl->current_test_info();
|
||||||
const int death_test_index = info->result()->death_test_count();
|
const int death_test_index = info->result()->death_test_count();
|
||||||
|
|
||||||
if (flag != NULL) {
|
if (flag != nullptr) {
|
||||||
set_write_fd(flag->write_fd());
|
set_write_fd(flag->write_fd());
|
||||||
return EXECUTE_TEST;
|
return EXECUTE_TEST;
|
||||||
}
|
}
|
||||||
|
@ -1133,9 +1419,9 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
|
||||||
// it be closed when the child process does an exec:
|
// it be closed when the child process does an exec:
|
||||||
GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
|
GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
|
||||||
|
|
||||||
const std::string filter_flag =
|
const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
|
||||||
std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
|
kFilterFlag + "=" + info->test_suite_name() +
|
||||||
+ info->test_case_name() + "." + info->name();
|
"." + info->name();
|
||||||
const std::string internal_flag =
|
const std::string internal_flag =
|
||||||
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
|
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
|
||||||
+ file_ + "|" + StreamableToString(line_) + "|"
|
+ file_ + "|" + StreamableToString(line_) + "|"
|
||||||
|
@ -1168,7 +1454,8 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
|
||||||
// by the "test" argument to its address. If the test should be
|
// by the "test" argument to its address. If the test should be
|
||||||
// skipped, sets that pointer to NULL. Returns true, unless the
|
// skipped, sets that pointer to NULL. Returns true, unless the
|
||||||
// flag is set to an invalid value.
|
// flag is set to an invalid value.
|
||||||
bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
|
bool DefaultDeathTestFactory::Create(const char* statement,
|
||||||
|
Matcher<const std::string&> matcher,
|
||||||
const char* file, int line,
|
const char* file, int line,
|
||||||
DeathTest** test) {
|
DeathTest** test) {
|
||||||
UnitTestImpl* const impl = GetUnitTestImpl();
|
UnitTestImpl* const impl = GetUnitTestImpl();
|
||||||
|
@ -1177,7 +1464,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
|
||||||
const int death_test_index = impl->current_test_info()
|
const int death_test_index = impl->current_test_info()
|
||||||
->increment_death_test_count();
|
->increment_death_test_count();
|
||||||
|
|
||||||
if (flag != NULL) {
|
if (flag != nullptr) {
|
||||||
if (death_test_index > flag->index()) {
|
if (death_test_index > flag->index()) {
|
||||||
DeathTest::set_last_death_test_message(
|
DeathTest::set_last_death_test_message(
|
||||||
"Death test count (" + StreamableToString(death_test_index)
|
"Death test count (" + StreamableToString(death_test_index)
|
||||||
|
@ -1188,7 +1475,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
|
||||||
|
|
||||||
if (!(flag->file() == file && flag->line() == line &&
|
if (!(flag->file() == file && flag->line() == line &&
|
||||||
flag->index() == death_test_index)) {
|
flag->index() == death_test_index)) {
|
||||||
*test = NULL;
|
*test = nullptr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1197,15 +1484,22 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
|
||||||
|
|
||||||
if (GTEST_FLAG(death_test_style) == "threadsafe" ||
|
if (GTEST_FLAG(death_test_style) == "threadsafe" ||
|
||||||
GTEST_FLAG(death_test_style) == "fast") {
|
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
|
# else
|
||||||
|
|
||||||
if (GTEST_FLAG(death_test_style) == "threadsafe") {
|
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") {
|
} else if (GTEST_FLAG(death_test_style) == "fast") {
|
||||||
*test = new NoExecDeathTest(statement, regex);
|
*test = new NoExecDeathTest(statement, std::move(matcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
# endif // GTEST_OS_WINDOWS
|
# endif // GTEST_OS_WINDOWS
|
||||||
|
@ -1224,7 +1518,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
|
||||||
// Recreates the pipe and event handles from the provided parameters,
|
// Recreates the pipe and event handles from the provided parameters,
|
||||||
// signals the event, and returns a file descriptor wrapped around the pipe
|
// signals the event, and returns a file descriptor wrapped around the pipe
|
||||||
// handle. This function is called in the child process only.
|
// 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 write_handle_as_size_t,
|
||||||
size_t event_handle_as_size_t) {
|
size_t event_handle_as_size_t) {
|
||||||
AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
|
AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
|
||||||
|
@ -1235,15 +1529,13 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
|
||||||
StreamableToString(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));
|
GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
|
||||||
|
|
||||||
const HANDLE write_handle =
|
const HANDLE write_handle =
|
||||||
reinterpret_cast<HANDLE>(write_handle_as_size_t);
|
reinterpret_cast<HANDLE>(write_handle_as_size_t);
|
||||||
HANDLE dup_write_handle;
|
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
|
// process. To obtain one accessible within the child, we need to use
|
||||||
// DuplicateHandle.
|
// DuplicateHandle.
|
||||||
if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
|
if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
|
||||||
|
@ -1292,7 +1584,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
|
||||||
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
|
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
|
||||||
// the flag is specified; otherwise returns NULL.
|
// the flag is specified; otherwise returns NULL.
|
||||||
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
|
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
|
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
|
||||||
// can use it here.
|
// can use it here.
|
||||||
|
@ -1320,6 +1612,16 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
|
||||||
write_fd = GetStatusFileDescriptor(parent_process_id,
|
write_fd = GetStatusFileDescriptor(parent_process_id,
|
||||||
write_handle_as_size_t,
|
write_handle_as_size_t,
|
||||||
event_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
|
# else
|
||||||
|
|
||||||
if (fields.size() != 4
|
if (fields.size() != 4
|
||||||
|
|
|
@ -26,28 +26,25 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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-filepath.h"
|
||||||
#include "gtest/internal/gtest-port.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
#include "gtest/gtest-message.h"
|
||||||
|
|
||||||
#if GTEST_OS_WINDOWS_MOBILE
|
#if GTEST_OS_WINDOWS_MOBILE
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#elif GTEST_OS_WINDOWS
|
#elif GTEST_OS_WINDOWS
|
||||||
# include <direct.h>
|
# include <direct.h>
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
#elif GTEST_OS_SYMBIAN
|
|
||||||
// Symbian OpenC has PATH_MAX in sys/syslimits.h
|
|
||||||
# include <sys/syslimits.h>
|
|
||||||
#else
|
#else
|
||||||
# include <limits.h>
|
# include <limits.h>
|
||||||
# include <climits> // Some Linux distributions define PATH_MAX here.
|
# include <climits> // Some Linux distributions define PATH_MAX here.
|
||||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-string.h"
|
||||||
|
|
||||||
#if GTEST_OS_WINDOWS
|
#if GTEST_OS_WINDOWS
|
||||||
# define GTEST_PATH_MAX_ _MAX_PATH
|
# define GTEST_PATH_MAX_ _MAX_PATH
|
||||||
#elif defined(PATH_MAX)
|
#elif defined(PATH_MAX)
|
||||||
|
@ -58,8 +55,6 @@
|
||||||
# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
|
# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
|
||||||
#endif // GTEST_OS_WINDOWS
|
#endif // GTEST_OS_WINDOWS
|
||||||
|
|
||||||
#include "gtest/internal/gtest-string.h"
|
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
@ -97,13 +92,15 @@ static bool IsPathSeparator(char c) {
|
||||||
|
|
||||||
// Returns the current working directory, or "" if unsuccessful.
|
// Returns the current working directory, or "" if unsuccessful.
|
||||||
FilePath FilePath::GetCurrentDir() {
|
FilePath FilePath::GetCurrentDir() {
|
||||||
#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
|
#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
|
||||||
// Windows CE doesn't have a current directory, so we just return
|
GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32 || \
|
||||||
|
GTEST_OS_XTENSA
|
||||||
|
// These platforms do not have a current directory, so we just return
|
||||||
// something reasonable.
|
// something reasonable.
|
||||||
return FilePath(kCurrentDirectoryString);
|
return FilePath(kCurrentDirectoryString);
|
||||||
#elif GTEST_OS_WINDOWS
|
#elif GTEST_OS_WINDOWS
|
||||||
char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
|
char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
|
||||||
return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
|
return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd);
|
||||||
#else
|
#else
|
||||||
char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
|
char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
|
||||||
char* result = getcwd(cwd, sizeof(cwd));
|
char* result = getcwd(cwd, sizeof(cwd));
|
||||||
|
@ -111,9 +108,9 @@ FilePath FilePath::GetCurrentDir() {
|
||||||
// getcwd will likely fail in NaCl due to the sandbox, so return something
|
// getcwd will likely fail in NaCl due to the sandbox, so return something
|
||||||
// reasonable. The user may have provided a shim implementation for getcwd,
|
// reasonable. The user may have provided a shim implementation for getcwd,
|
||||||
// however, so fallback only when failure is detected.
|
// however, so fallback only when failure is detected.
|
||||||
return FilePath(result == NULL ? kCurrentDirectoryString : cwd);
|
return FilePath(result == nullptr ? kCurrentDirectoryString : cwd);
|
||||||
# endif // GTEST_OS_NACL
|
# endif // GTEST_OS_NACL
|
||||||
return FilePath(result == NULL ? "" : cwd);
|
return FilePath(result == nullptr ? "" : cwd);
|
||||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +127,7 @@ FilePath FilePath::RemoveExtension(const char* extension) const {
|
||||||
return *this;
|
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
|
// the FilePath. On Windows, for example, both '/' and '\' are valid path
|
||||||
// separators. Returns NULL if no path separator was found.
|
// separators. Returns NULL if no path separator was found.
|
||||||
const char* FilePath::FindLastPathSeparator() const {
|
const char* FilePath::FindLastPathSeparator() const {
|
||||||
|
@ -138,8 +135,8 @@ const char* FilePath::FindLastPathSeparator() const {
|
||||||
#if GTEST_HAS_ALT_PATH_SEP_
|
#if GTEST_HAS_ALT_PATH_SEP_
|
||||||
const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
|
const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
|
||||||
// Comparing two pointers of which only one is NULL is undefined.
|
// Comparing two pointers of which only one is NULL is undefined.
|
||||||
if (last_alt_sep != NULL &&
|
if (last_alt_sep != nullptr &&
|
||||||
(last_sep == NULL || last_alt_sep > last_sep)) {
|
(last_sep == nullptr || last_alt_sep > last_sep)) {
|
||||||
return last_alt_sep;
|
return last_alt_sep;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -167,7 +164,7 @@ FilePath FilePath::RemoveFileName() const {
|
||||||
const char* const last_sep = FindLastPathSeparator();
|
const char* const last_sep = FindLastPathSeparator();
|
||||||
std::string dir;
|
std::string dir;
|
||||||
if (last_sep) {
|
if (last_sep) {
|
||||||
dir = std::string(c_str(), last_sep + 1 - c_str());
|
dir = std::string(c_str(), static_cast<size_t>(last_sep + 1 - c_str()));
|
||||||
} else {
|
} else {
|
||||||
dir = kCurrentDirectoryString;
|
dir = kCurrentDirectoryString;
|
||||||
}
|
}
|
||||||
|
@ -213,7 +210,7 @@ bool FilePath::FileOrDirectoryExists() const {
|
||||||
delete [] unicode;
|
delete [] unicode;
|
||||||
return attributes != kInvalidFileAttributes;
|
return attributes != kInvalidFileAttributes;
|
||||||
#else
|
#else
|
||||||
posix::StatStruct file_stat;
|
posix::StatStruct file_stat{};
|
||||||
return posix::Stat(pathname_.c_str(), &file_stat) == 0;
|
return posix::Stat(pathname_.c_str(), &file_stat) == 0;
|
||||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||||
}
|
}
|
||||||
|
@ -240,7 +237,7 @@ bool FilePath::DirectoryExists() const {
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
posix::StatStruct file_stat;
|
posix::StatStruct file_stat{};
|
||||||
result = posix::Stat(path.c_str(), &file_stat) == 0 &&
|
result = posix::Stat(path.c_str(), &file_stat) == 0 &&
|
||||||
posix::IsDir(file_stat);
|
posix::IsDir(file_stat);
|
||||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||||
|
@ -252,9 +249,6 @@ bool FilePath::DirectoryExists() const {
|
||||||
// root directory per disk drive.)
|
// root directory per disk drive.)
|
||||||
bool FilePath::IsRootDirectory() const {
|
bool FilePath::IsRootDirectory() const {
|
||||||
#if GTEST_OS_WINDOWS
|
#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();
|
return pathname_.length() == 3 && IsAbsolutePath();
|
||||||
#else
|
#else
|
||||||
return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
|
return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
|
||||||
|
@ -326,10 +320,13 @@ bool FilePath::CreateFolder() const {
|
||||||
#if GTEST_OS_WINDOWS_MOBILE
|
#if GTEST_OS_WINDOWS_MOBILE
|
||||||
FilePath removed_sep(this->RemoveTrailingPathSeparator());
|
FilePath removed_sep(this->RemoveTrailingPathSeparator());
|
||||||
LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
|
LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
|
||||||
int result = CreateDirectory(unicode, NULL) ? 0 : -1;
|
int result = CreateDirectory(unicode, nullptr) ? 0 : -1;
|
||||||
delete [] unicode;
|
delete [] unicode;
|
||||||
#elif GTEST_OS_WINDOWS
|
#elif GTEST_OS_WINDOWS
|
||||||
int result = _mkdir(pathname_.c_str());
|
int result = _mkdir(pathname_.c_str());
|
||||||
|
#elif GTEST_OS_ESP8266 || GTEST_OS_XTENSA
|
||||||
|
// do nothing
|
||||||
|
int result = 0;
|
||||||
#else
|
#else
|
||||||
int result = mkdir(pathname_.c_str(), 0777);
|
int result = mkdir(pathname_.c_str(), 0777);
|
||||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||||
|
@ -352,35 +349,20 @@ FilePath FilePath::RemoveTrailingPathSeparator() const {
|
||||||
// Removes any redundant separators that might be in the pathname.
|
// Removes any redundant separators that might be in the pathname.
|
||||||
// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
|
// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
|
||||||
// redundancies that might be in a pathname involving "." or "..".
|
// redundancies that might be in a pathname involving "." or "..".
|
||||||
// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
|
|
||||||
void FilePath::Normalize() {
|
void FilePath::Normalize() {
|
||||||
if (pathname_.c_str() == NULL) {
|
auto out = pathname_.begin();
|
||||||
pathname_ = "";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const char* src = pathname_.c_str();
|
|
||||||
char* const dest = new char[pathname_.length() + 1];
|
|
||||||
char* dest_ptr = dest;
|
|
||||||
memset(dest_ptr, 0, pathname_.length() + 1);
|
|
||||||
|
|
||||||
while (*src != '\0') {
|
for (const char character : pathname_) {
|
||||||
*dest_ptr = *src;
|
if (!IsPathSeparator(character)) {
|
||||||
if (!IsPathSeparator(*src)) {
|
*(out++) = character;
|
||||||
src++;
|
} else if (out == pathname_.begin() || *std::prev(out) != kPathSeparator) {
|
||||||
|
*(out++) = kPathSeparator;
|
||||||
} else {
|
} else {
|
||||||
#if GTEST_HAS_ALT_PATH_SEP_
|
continue;
|
||||||
if (*dest_ptr == kAlternatePathSeparator) {
|
|
||||||
*dest_ptr = kPathSeparator;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
while (IsPathSeparator(*src))
|
|
||||||
src++;
|
|
||||||
}
|
}
|
||||||
dest_ptr++;
|
|
||||||
}
|
}
|
||||||
*dest_ptr = '\0';
|
|
||||||
pathname_ = dest;
|
pathname_.erase(out, pathname_.end());
|
||||||
delete[] dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
|
@ -27,23 +27,12 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Utility functions and classes used by the Google C++ testing framework.
|
// Utility functions and classes used by the Google C++ testing framework.//
|
||||||
//
|
|
||||||
// Author: wan@google.com (Zhanyong Wan)
|
|
||||||
//
|
|
||||||
// This file contains purely Google Test's internal implementation. Please
|
// This file contains purely Google Test's internal implementation. Please
|
||||||
// DO NOT #INCLUDE IT IN A USER PROGRAM.
|
// DO NOT #INCLUDE IT IN A USER PROGRAM.
|
||||||
|
|
||||||
#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
|
#ifndef GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
|
||||||
#define GTEST_SRC_GTEST_INTERNAL_INL_H_
|
#define GOOGLETEST_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_
|
|
||||||
// If this file is included from the user's 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
|
#ifndef _WIN32_WCE
|
||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
|
@ -53,6 +42,8 @@
|
||||||
#include <string.h> // For memmove.
|
#include <string.h> // For memmove.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -67,9 +58,12 @@
|
||||||
# include <windows.h> // NOLINT
|
# include <windows.h> // NOLINT
|
||||||
#endif // GTEST_OS_WINDOWS
|
#endif // GTEST_OS_WINDOWS
|
||||||
|
|
||||||
#include "gtest/gtest.h" // NOLINT
|
#include "gtest/gtest.h"
|
||||||
#include "gtest/gtest-spi.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 {
|
namespace testing {
|
||||||
|
|
||||||
// Declares the flags.
|
// Declares the flags.
|
||||||
|
@ -90,10 +84,13 @@ const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
|
||||||
const char kBreakOnFailureFlag[] = "break_on_failure";
|
const char kBreakOnFailureFlag[] = "break_on_failure";
|
||||||
const char kCatchExceptionsFlag[] = "catch_exceptions";
|
const char kCatchExceptionsFlag[] = "catch_exceptions";
|
||||||
const char kColorFlag[] = "color";
|
const char kColorFlag[] = "color";
|
||||||
|
const char kFailFast[] = "fail_fast";
|
||||||
const char kFilterFlag[] = "filter";
|
const char kFilterFlag[] = "filter";
|
||||||
const char kListTestsFlag[] = "list_tests";
|
const char kListTestsFlag[] = "list_tests";
|
||||||
const char kOutputFlag[] = "output";
|
const char kOutputFlag[] = "output";
|
||||||
|
const char kBriefFlag[] = "brief";
|
||||||
const char kPrintTimeFlag[] = "print_time";
|
const char kPrintTimeFlag[] = "print_time";
|
||||||
|
const char kPrintUTF8Flag[] = "print_utf8";
|
||||||
const char kRandomSeedFlag[] = "random_seed";
|
const char kRandomSeedFlag[] = "random_seed";
|
||||||
const char kRepeatFlag[] = "repeat";
|
const char kRepeatFlag[] = "repeat";
|
||||||
const char kShuffleFlag[] = "shuffle";
|
const char kShuffleFlag[] = "shuffle";
|
||||||
|
@ -105,14 +102,14 @@ const char kFlagfileFlag[] = "flagfile";
|
||||||
// A valid random seed must be in [1, kMaxRandomSeed].
|
// A valid random seed must be in [1, kMaxRandomSeed].
|
||||||
const int kMaxRandomSeed = 99999;
|
const int kMaxRandomSeed = 99999;
|
||||||
|
|
||||||
// g_help_flag is true iff the --help flag or an equivalent form is
|
// g_help_flag is true if and only if the --help flag or an equivalent form
|
||||||
// specified on the command line.
|
// is specified on the command line.
|
||||||
GTEST_API_ extern bool g_help_flag;
|
GTEST_API_ extern bool g_help_flag;
|
||||||
|
|
||||||
// Returns the current time in milliseconds.
|
// Returns the current time in milliseconds.
|
||||||
GTEST_API_ TimeInMillis GetTimeInMillis();
|
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);
|
GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
|
||||||
|
|
||||||
// Formats the given time in milliseconds as seconds.
|
// Formats the given time in milliseconds as seconds.
|
||||||
|
@ -129,11 +126,11 @@ GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);
|
||||||
// On success, stores the value of the flag in *value, and returns
|
// On success, stores the value of the flag in *value, and returns
|
||||||
// true. On failure, returns false without changing *value.
|
// true. On failure, returns false without changing *value.
|
||||||
GTEST_API_ bool ParseInt32Flag(
|
GTEST_API_ bool ParseInt32Flag(
|
||||||
const char* str, const char* flag, Int32* value);
|
const char* str, const char* flag, int32_t* value);
|
||||||
|
|
||||||
// Returns a random seed in range [1, kMaxRandomSeed] based on the
|
// Returns a random seed in range [1, kMaxRandomSeed] based on the
|
||||||
// given --gtest_random_seed flag value.
|
// given --gtest_random_seed flag value.
|
||||||
inline int GetRandomSeedFromFlag(Int32 random_seed_flag) {
|
inline int GetRandomSeedFromFlag(int32_t random_seed_flag) {
|
||||||
const unsigned int raw_seed = (random_seed_flag == 0) ?
|
const unsigned int raw_seed = (random_seed_flag == 0) ?
|
||||||
static_cast<unsigned int>(GetTimeInMillis()) :
|
static_cast<unsigned int>(GetTimeInMillis()) :
|
||||||
static_cast<unsigned int>(random_seed_flag);
|
static_cast<unsigned int>(random_seed_flag);
|
||||||
|
@ -169,11 +166,14 @@ class GTestFlagSaver {
|
||||||
color_ = GTEST_FLAG(color);
|
color_ = GTEST_FLAG(color);
|
||||||
death_test_style_ = GTEST_FLAG(death_test_style);
|
death_test_style_ = GTEST_FLAG(death_test_style);
|
||||||
death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
|
death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
|
||||||
|
fail_fast_ = GTEST_FLAG(fail_fast);
|
||||||
filter_ = GTEST_FLAG(filter);
|
filter_ = GTEST_FLAG(filter);
|
||||||
internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
|
internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
|
||||||
list_tests_ = GTEST_FLAG(list_tests);
|
list_tests_ = GTEST_FLAG(list_tests);
|
||||||
output_ = GTEST_FLAG(output);
|
output_ = GTEST_FLAG(output);
|
||||||
|
brief_ = GTEST_FLAG(brief);
|
||||||
print_time_ = GTEST_FLAG(print_time);
|
print_time_ = GTEST_FLAG(print_time);
|
||||||
|
print_utf8_ = GTEST_FLAG(print_utf8);
|
||||||
random_seed_ = GTEST_FLAG(random_seed);
|
random_seed_ = GTEST_FLAG(random_seed);
|
||||||
repeat_ = GTEST_FLAG(repeat);
|
repeat_ = GTEST_FLAG(repeat);
|
||||||
shuffle_ = GTEST_FLAG(shuffle);
|
shuffle_ = GTEST_FLAG(shuffle);
|
||||||
|
@ -191,10 +191,13 @@ class GTestFlagSaver {
|
||||||
GTEST_FLAG(death_test_style) = death_test_style_;
|
GTEST_FLAG(death_test_style) = death_test_style_;
|
||||||
GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
|
GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
|
||||||
GTEST_FLAG(filter) = filter_;
|
GTEST_FLAG(filter) = filter_;
|
||||||
|
GTEST_FLAG(fail_fast) = fail_fast_;
|
||||||
GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
|
GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
|
||||||
GTEST_FLAG(list_tests) = list_tests_;
|
GTEST_FLAG(list_tests) = list_tests_;
|
||||||
GTEST_FLAG(output) = output_;
|
GTEST_FLAG(output) = output_;
|
||||||
|
GTEST_FLAG(brief) = brief_;
|
||||||
GTEST_FLAG(print_time) = print_time_;
|
GTEST_FLAG(print_time) = print_time_;
|
||||||
|
GTEST_FLAG(print_utf8) = print_utf8_;
|
||||||
GTEST_FLAG(random_seed) = random_seed_;
|
GTEST_FLAG(random_seed) = random_seed_;
|
||||||
GTEST_FLAG(repeat) = repeat_;
|
GTEST_FLAG(repeat) = repeat_;
|
||||||
GTEST_FLAG(shuffle) = shuffle_;
|
GTEST_FLAG(shuffle) = shuffle_;
|
||||||
|
@ -211,15 +214,18 @@ class GTestFlagSaver {
|
||||||
std::string color_;
|
std::string color_;
|
||||||
std::string death_test_style_;
|
std::string death_test_style_;
|
||||||
bool death_test_use_fork_;
|
bool death_test_use_fork_;
|
||||||
|
bool fail_fast_;
|
||||||
std::string filter_;
|
std::string filter_;
|
||||||
std::string internal_run_death_test_;
|
std::string internal_run_death_test_;
|
||||||
bool list_tests_;
|
bool list_tests_;
|
||||||
std::string output_;
|
std::string output_;
|
||||||
|
bool brief_;
|
||||||
bool print_time_;
|
bool print_time_;
|
||||||
internal::Int32 random_seed_;
|
bool print_utf8_;
|
||||||
internal::Int32 repeat_;
|
int32_t random_seed_;
|
||||||
|
int32_t repeat_;
|
||||||
bool shuffle_;
|
bool shuffle_;
|
||||||
internal::Int32 stack_trace_depth_;
|
int32_t stack_trace_depth_;
|
||||||
std::string stream_result_to_;
|
std::string stream_result_to_;
|
||||||
bool throw_on_failure_;
|
bool throw_on_failure_;
|
||||||
} GTEST_ATTRIBUTE_UNUSED_;
|
} GTEST_ATTRIBUTE_UNUSED_;
|
||||||
|
@ -230,11 +236,11 @@ class GTestFlagSaver {
|
||||||
// If the code_point is not a valid Unicode code point
|
// If the code_point is not a valid Unicode code point
|
||||||
// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
|
// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
|
||||||
// to "(Invalid Unicode 0xXXXXXXXX)".
|
// to "(Invalid Unicode 0xXXXXXXXX)".
|
||||||
GTEST_API_ std::string CodePointToUtf8(UInt32 code_point);
|
GTEST_API_ std::string CodePointToUtf8(uint32_t code_point);
|
||||||
|
|
||||||
// Converts a wide string to a narrow string in UTF-8 encoding.
|
// Converts a wide string to a narrow string in UTF-8 encoding.
|
||||||
// The wide string is assumed to have the following 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)
|
// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
|
||||||
// Parameter str points to a null-terminated wide string.
|
// Parameter str points to a null-terminated wide string.
|
||||||
// Parameter num_chars may additionally limit the number
|
// Parameter num_chars may additionally limit the number
|
||||||
|
@ -263,14 +269,14 @@ GTEST_API_ bool ShouldShard(const char* total_shards_str,
|
||||||
const char* shard_index_str,
|
const char* shard_index_str,
|
||||||
bool in_subprocess_for_death_test);
|
bool in_subprocess_for_death_test);
|
||||||
|
|
||||||
// Parses the environment variable var as an Int32. If it is unset,
|
// Parses the environment variable var as a 32-bit integer. If it is unset,
|
||||||
// returns default_val. If it is not an Int32, prints an error and
|
// returns default_val. If it is not a 32-bit integer, prints an error and
|
||||||
// and aborts.
|
// and aborts.
|
||||||
GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
|
GTEST_API_ int32_t Int32FromEnvOrDie(const char* env_var, int32_t default_val);
|
||||||
|
|
||||||
// Given the total number of shards, the shard index, and the test id,
|
// 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
|
// returns true if and only if the test should be run on this shard. The test id
|
||||||
// some arbitrary but unique non-negative integer assigned to each test
|
// is some arbitrary but unique non-negative integer assigned to each test
|
||||||
// method. Assumes that 0 <= shard_index < total_shards.
|
// method. Assumes that 0 <= shard_index < total_shards.
|
||||||
GTEST_API_ bool ShouldRunTestOnShard(
|
GTEST_API_ bool ShouldRunTestOnShard(
|
||||||
int total_shards, int shard_index, int test_id);
|
int total_shards, int shard_index, int test_id);
|
||||||
|
@ -301,7 +307,8 @@ void ForEach(const Container& c, Functor functor) {
|
||||||
// in range [0, v.size()).
|
// in range [0, v.size()).
|
||||||
template <typename E>
|
template <typename E>
|
||||||
inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
|
inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
|
||||||
return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
|
return (i < 0 || i >= static_cast<int>(v.size())) ? default_value
|
||||||
|
: v[static_cast<size_t>(i)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs an in-place shuffle of a range of the vector's elements.
|
// Performs an in-place shuffle of a range of the vector's elements.
|
||||||
|
@ -323,8 +330,11 @@ void ShuffleRange(internal::Random* random, int begin, int end,
|
||||||
// http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
|
// http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
|
||||||
for (int range_width = end - begin; range_width >= 2; range_width--) {
|
for (int range_width = end - begin; range_width >= 2; range_width--) {
|
||||||
const int last_in_range = begin + range_width - 1;
|
const int last_in_range = begin + range_width - 1;
|
||||||
const int selected = begin + random->Generate(range_width);
|
const int selected =
|
||||||
std::swap((*v)[selected], (*v)[last_in_range]);
|
begin +
|
||||||
|
static_cast<int>(random->Generate(static_cast<uint32_t>(range_width)));
|
||||||
|
std::swap((*v)[static_cast<size_t>(selected)],
|
||||||
|
(*v)[static_cast<size_t>(last_in_range)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +361,7 @@ class TestPropertyKeyIs {
|
||||||
// TestPropertyKeyIs has NO default constructor.
|
// TestPropertyKeyIs has NO default constructor.
|
||||||
explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}
|
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 {
|
bool operator()(const TestProperty& test_property) const {
|
||||||
return test_property.key() == key_;
|
return test_property.key() == key_;
|
||||||
}
|
}
|
||||||
|
@ -384,17 +394,10 @@ class GTEST_API_ UnitTestOptions {
|
||||||
|
|
||||||
// Functions for processing the gtest_filter flag.
|
// Functions for processing the gtest_filter flag.
|
||||||
|
|
||||||
// Returns true iff the wildcard pattern matches the string. The
|
// Returns true if and only if the user-specified filter matches the test
|
||||||
// first ':' or '\0' character in pattern marks the end of it.
|
// suite name and the test name.
|
||||||
//
|
static bool FilterMatchesTest(const std::string& test_suite_name,
|
||||||
// This recursive algorithm isn't very efficient, but is clear and
|
const std::string& test_name);
|
||||||
// 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);
|
|
||||||
|
|
||||||
#if GTEST_OS_WINDOWS
|
#if GTEST_OS_WINDOWS
|
||||||
// Function for supporting the gtest_catch_exception flag.
|
// Function for supporting the gtest_catch_exception flag.
|
||||||
|
@ -426,7 +429,7 @@ class OsStackTraceGetterInterface {
|
||||||
// in the trace.
|
// in the trace.
|
||||||
// skip_count - the number of top frames to be skipped; doesn't count
|
// skip_count - the number of top frames to be skipped; doesn't count
|
||||||
// against max_depth.
|
// 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
|
// UponLeavingGTest() should be called immediately before Google Test calls
|
||||||
// user code. It saves some information about the current stack that
|
// user code. It saves some information about the current stack that
|
||||||
|
@ -446,10 +449,20 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface {
|
||||||
public:
|
public:
|
||||||
OsStackTraceGetter() {}
|
OsStackTraceGetter() {}
|
||||||
|
|
||||||
virtual string CurrentStackTrace(int max_depth, int skip_count);
|
std::string CurrentStackTrace(int max_depth, int skip_count) override;
|
||||||
virtual void UponLeavingGTest();
|
void UponLeavingGTest() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#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 the stack trace code from within the user code.
|
||||||
|
void* caller_frame_ = nullptr;
|
||||||
|
#endif // GTEST_HAS_ABSL
|
||||||
|
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -468,7 +481,7 @@ class DefaultGlobalTestPartResultReporter
|
||||||
explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
|
explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
|
||||||
// Implements the TestPartResultReporterInterface. Reports the test part
|
// Implements the TestPartResultReporterInterface. Reports the test part
|
||||||
// result in the current test.
|
// result in the current test.
|
||||||
virtual void ReportTestPartResult(const TestPartResult& result);
|
void ReportTestPartResult(const TestPartResult& result) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UnitTestImpl* const unit_test_;
|
UnitTestImpl* const unit_test_;
|
||||||
|
@ -484,7 +497,7 @@ class DefaultPerThreadTestPartResultReporter
|
||||||
explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
|
explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
|
||||||
// Implements the TestPartResultReporterInterface. The implementation just
|
// Implements the TestPartResultReporterInterface. The implementation just
|
||||||
// delegates to the current global test part result reporter of *unit_test_.
|
// 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:
|
private:
|
||||||
UnitTestImpl* const unit_test_;
|
UnitTestImpl* const unit_test_;
|
||||||
|
@ -522,22 +535,25 @@ class GTEST_API_ UnitTestImpl {
|
||||||
void SetTestPartResultReporterForCurrentThread(
|
void SetTestPartResultReporterForCurrentThread(
|
||||||
TestPartResultReporterInterface* reporter);
|
TestPartResultReporterInterface* reporter);
|
||||||
|
|
||||||
// Gets the number of successful test cases.
|
// Gets the number of successful test suites.
|
||||||
int successful_test_case_count() const;
|
int successful_test_suite_count() const;
|
||||||
|
|
||||||
// Gets the number of failed test cases.
|
// Gets the number of failed test suites.
|
||||||
int failed_test_case_count() const;
|
int failed_test_suite_count() const;
|
||||||
|
|
||||||
// Gets the number of all test cases.
|
// Gets the number of all test suites.
|
||||||
int total_test_case_count() const;
|
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.
|
// that should run.
|
||||||
int test_case_to_run_count() const;
|
int test_suite_to_run_count() const;
|
||||||
|
|
||||||
// Gets the number of successful tests.
|
// Gets the number of successful tests.
|
||||||
int successful_test_count() const;
|
int successful_test_count() const;
|
||||||
|
|
||||||
|
// Gets the number of skipped tests.
|
||||||
|
int skipped_test_count() const;
|
||||||
|
|
||||||
// Gets the number of failed tests.
|
// Gets the number of failed tests.
|
||||||
int failed_test_count() const;
|
int failed_test_count() const;
|
||||||
|
|
||||||
|
@ -563,27 +579,33 @@ class GTEST_API_ UnitTestImpl {
|
||||||
// Gets the elapsed time, in milliseconds.
|
// Gets the elapsed time, in milliseconds.
|
||||||
TimeInMillis elapsed_time() const { return elapsed_time_; }
|
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(); }
|
bool Passed() const { return !Failed(); }
|
||||||
|
|
||||||
// Returns true iff the unit test failed (i.e. some test case failed
|
// Returns true if and only if the unit test failed (i.e. some test suite
|
||||||
// or something outside of all tests failed).
|
// failed or something outside of all tests failed).
|
||||||
bool Failed() const {
|
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
|
// Gets the i-th test suite among all the test suites. i can range from 0 to
|
||||||
// total_test_case_count() - 1. If i is not in that range, returns NULL.
|
// total_test_suite_count() - 1. If i is not in that range, returns NULL.
|
||||||
const TestCase* GetTestCase(int i) const {
|
const TestSuite* GetTestSuite(int i) const {
|
||||||
const int index = GetElementOr(test_case_indices_, i, -1);
|
const int index = GetElementOr(test_suite_indices_, i, -1);
|
||||||
return index < 0 ? NULL : test_cases_[i];
|
return index < 0 ? nullptr : test_suites_[static_cast<size_t>(i)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the i-th test case among all the test cases. i can range from 0 to
|
// Legacy API is deprecated but still available
|
||||||
// total_test_case_count() - 1. If i is not in that range, returns NULL.
|
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
TestCase* GetMutableTestCase(int i) {
|
const TestCase* GetTestCase(int i) const { return GetTestSuite(i); }
|
||||||
const int index = GetElementOr(test_case_indices_, i, -1);
|
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
return index < 0 ? NULL : test_cases_[index];
|
|
||||||
|
// 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<size_t>(index)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provides access to the event listener list.
|
// Provides access to the event listener list.
|
||||||
|
@ -620,31 +642,40 @@ class GTEST_API_ UnitTestImpl {
|
||||||
// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
|
// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
|
||||||
std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;
|
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.
|
// exist, creates one and returns it.
|
||||||
//
|
//
|
||||||
// Arguments:
|
// 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
|
// type_param: the name of the test's type parameter, or NULL if
|
||||||
// this is not a typed or a type-parameterized test.
|
// this is not a typed or a type-parameterized test.
|
||||||
// set_up_tc: pointer to the function that sets up 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 case
|
// tear_down_tc: pointer to the function that tears down the test suite
|
||||||
TestCase* GetTestCase(const char* test_case_name,
|
TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param,
|
||||||
const char* type_param,
|
internal::SetUpTestSuiteFunc set_up_tc,
|
||||||
Test::SetUpTestCaseFunc set_up_tc,
|
internal::TearDownTestSuiteFunc tear_down_tc);
|
||||||
Test::TearDownTestCaseFunc 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.
|
// Adds a TestInfo to the unit test.
|
||||||
//
|
//
|
||||||
// Arguments:
|
// Arguments:
|
||||||
//
|
//
|
||||||
// set_up_tc: pointer to the function that sets up 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 case
|
// tear_down_tc: pointer to the function that tears down the test suite
|
||||||
// test_info: the TestInfo object
|
// test_info: the TestInfo object
|
||||||
void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
|
void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc,
|
||||||
Test::TearDownTestCaseFunc tear_down_tc,
|
internal::TearDownTestSuiteFunc tear_down_tc,
|
||||||
TestInfo* test_info) {
|
TestInfo* test_info) {
|
||||||
|
#if GTEST_HAS_DEATH_TEST
|
||||||
// In order to support thread-safe death tests, we need to
|
// In order to support thread-safe death tests, we need to
|
||||||
// remember the original working directory when the test program
|
// remember the original working directory when the test program
|
||||||
// was first invoked. We cannot do this in RUN_ALL_TESTS(), as
|
// was first invoked. We cannot do this in RUN_ALL_TESTS(), as
|
||||||
|
@ -657,24 +688,33 @@ class GTEST_API_ UnitTestImpl {
|
||||||
GTEST_CHECK_(!original_working_dir_.IsEmpty())
|
GTEST_CHECK_(!original_working_dir_.IsEmpty())
|
||||||
<< "Failed to get the current working directory.";
|
<< "Failed to get the current working directory.";
|
||||||
}
|
}
|
||||||
|
#endif // GTEST_HAS_DEATH_TEST
|
||||||
|
|
||||||
GetTestCase(test_info->test_case_name(),
|
GetTestSuite(test_info->test_suite_name(), test_info->type_param(),
|
||||||
test_info->type_param(),
|
set_up_tc, tear_down_tc)
|
||||||
set_up_tc,
|
->AddTestInfo(test_info);
|
||||||
tear_down_tc)->AddTestInfo(test_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GTEST_HAS_PARAM_TEST
|
// Returns ParameterizedTestSuiteRegistry object used to keep track of
|
||||||
// Returns ParameterizedTestCaseRegistry object used to keep track of
|
|
||||||
// value-parameterized tests and instantiate and register them.
|
// value-parameterized tests and instantiate and register them.
|
||||||
internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
|
internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() {
|
||||||
return parameterized_test_registry_;
|
return parameterized_test_registry_;
|
||||||
}
|
}
|
||||||
#endif // GTEST_HAS_PARAM_TEST
|
|
||||||
|
|
||||||
// Sets the TestCase object for the test that's currently running.
|
std::set<std::string>* ignored_parameterized_test_suites() {
|
||||||
void set_current_test_case(TestCase* a_current_test_case) {
|
return &ignored_parameterized_test_suites_;
|
||||||
current_test_case_ = a_current_test_case;
|
}
|
||||||
|
|
||||||
|
// Returns TypeParameterizedTestSuiteRegistry object used to keep track of
|
||||||
|
// type-parameterized tests and instantiations of them.
|
||||||
|
internal::TypeParameterizedTestSuiteRegistry&
|
||||||
|
type_parameterized_test_registry() {
|
||||||
|
return type_parameterized_test_registry_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// Sets the TestInfo object for the test that's currently running. If
|
||||||
|
@ -685,7 +725,7 @@ class GTEST_API_ UnitTestImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registers all parameterized tests defined using TEST_P and
|
// 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
|
// combination. This method can be called more then once; it has guards
|
||||||
// protecting from registering the tests more then once. If
|
// protecting from registering the tests more then once. If
|
||||||
// value-parameterized tests are disabled, RegisterParameterizedTests is
|
// value-parameterized tests are disabled, RegisterParameterizedTests is
|
||||||
|
@ -700,7 +740,7 @@ class GTEST_API_ UnitTestImpl {
|
||||||
|
|
||||||
// Clears the results of all tests, except the ad hoc tests.
|
// Clears the results of all tests, except the ad hoc tests.
|
||||||
void ClearNonAdHocTestResult() {
|
void ClearNonAdHocTestResult() {
|
||||||
ForEach(test_cases_, TestCase::ClearTestCaseResult);
|
ForEach(test_suites_, TestSuite::ClearTestSuiteResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears the results of ad-hoc test assertions.
|
// Clears the results of ad-hoc test assertions.
|
||||||
|
@ -709,7 +749,7 @@ class GTEST_API_ UnitTestImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a TestProperty to the current TestResult object when invoked in a
|
// 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
|
// result already contains a property with the same key, the value will be
|
||||||
// updated.
|
// updated.
|
||||||
void RecordProperty(const TestProperty& test_property);
|
void RecordProperty(const TestProperty& test_property);
|
||||||
|
@ -721,7 +761,7 @@ class GTEST_API_ UnitTestImpl {
|
||||||
|
|
||||||
// Matches the full name of each test against the user-specified
|
// Matches the full name of each test against the user-specified
|
||||||
// filter to decide whether the test should run, then records the
|
// 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
|
// If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
|
||||||
// based on sharding variables in the environment.
|
// based on sharding variables in the environment.
|
||||||
// Returns the number of tests that should run.
|
// Returns the number of tests that should run.
|
||||||
|
@ -730,7 +770,7 @@ class GTEST_API_ UnitTestImpl {
|
||||||
// Prints the names of the tests matching the user-specified filter flag.
|
// Prints the names of the tests matching the user-specified filter flag.
|
||||||
void ListTestsMatchingFilter();
|
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_; }
|
TestInfo* current_test_info() { return current_test_info_; }
|
||||||
const TestInfo* current_test_info() const { return current_test_info_; }
|
const TestInfo* current_test_info() const { return current_test_info_; }
|
||||||
|
|
||||||
|
@ -791,11 +831,11 @@ class GTEST_API_ UnitTestImpl {
|
||||||
// Gets the random number generator.
|
// Gets the random number generator.
|
||||||
internal::Random* random() { return &random_; }
|
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.
|
// making sure that death tests are still run first.
|
||||||
void ShuffleTests();
|
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();
|
void UnshuffleTests();
|
||||||
|
|
||||||
// Returns the value of GTEST_FLAG(catch_exceptions) at the moment
|
// Returns the value of GTEST_FLAG(catch_exceptions) at the moment
|
||||||
|
@ -835,33 +875,37 @@ class GTEST_API_ UnitTestImpl {
|
||||||
// before/after the tests are run.
|
// before/after the tests are run.
|
||||||
std::vector<Environment*> environments_;
|
std::vector<Environment*> 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.
|
// elements in the vector.
|
||||||
std::vector<TestCase*> test_cases_;
|
std::vector<TestSuite*> test_suites_;
|
||||||
|
|
||||||
// Provides a level of indirection for the test case list to allow
|
// Provides a level of indirection for the test suite list to allow
|
||||||
// easy shuffling and restoring the test case order. The i-th
|
// easy shuffling and restoring the test suite order. The i-th
|
||||||
// element of this vector is the index of the i-th test case in the
|
// element of this vector is the index of the i-th test suite in the
|
||||||
// shuffled order.
|
// shuffled order.
|
||||||
std::vector<int> test_case_indices_;
|
std::vector<int> test_suite_indices_;
|
||||||
|
|
||||||
#if GTEST_HAS_PARAM_TEST
|
|
||||||
// ParameterizedTestRegistry object used to register value-parameterized
|
// ParameterizedTestRegistry object used to register value-parameterized
|
||||||
// tests.
|
// tests.
|
||||||
internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
|
internal::ParameterizedTestSuiteRegistry parameterized_test_registry_;
|
||||||
|
internal::TypeParameterizedTestSuiteRegistry
|
||||||
|
type_parameterized_test_registry_;
|
||||||
|
|
||||||
|
// The set holding the name of parameterized
|
||||||
|
// test suites that may go uninstantiated.
|
||||||
|
std::set<std::string> ignored_parameterized_test_suites_;
|
||||||
|
|
||||||
// Indicates whether RegisterParameterizedTests() has been called already.
|
// Indicates whether RegisterParameterizedTests() has been called already.
|
||||||
bool parameterized_tests_registered_;
|
bool parameterized_tests_registered_;
|
||||||
#endif // GTEST_HAS_PARAM_TEST
|
|
||||||
|
|
||||||
// Index of the last death test case registered. Initially -1.
|
// Index of the last death test suite registered. Initially -1.
|
||||||
int last_death_test_case_;
|
int last_death_test_suite_;
|
||||||
|
|
||||||
// This points to the TestCase for the currently running test. It
|
// This points to the TestSuite for the currently running test. It
|
||||||
// changes as Google Test goes through one test case after another.
|
// changes as Google Test goes through one test suite after another.
|
||||||
// When no test is running, this is set to NULL and Google Test
|
// When no test is running, this is set to NULL and Google Test
|
||||||
// stores assertion results in ad_hoc_test_result_. Initially NULL.
|
// 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
|
// This points to the TestInfo for the currently running test. It
|
||||||
// changes as Google Test goes through one test after another. When
|
// changes as Google Test goes through one test after another. When
|
||||||
|
@ -889,7 +933,7 @@ class GTEST_API_ UnitTestImpl {
|
||||||
// desired.
|
// desired.
|
||||||
OsStackTraceGetterInterface* os_stack_trace_getter_;
|
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_;
|
bool post_flag_parse_init_performed_;
|
||||||
|
|
||||||
// The random number seed used at the beginning of the test run.
|
// The random number seed used at the beginning of the test run.
|
||||||
|
@ -908,8 +952,8 @@ class GTEST_API_ UnitTestImpl {
|
||||||
#if GTEST_HAS_DEATH_TEST
|
#if GTEST_HAS_DEATH_TEST
|
||||||
// The decomposed components of the gtest_internal_run_death_test flag,
|
// The decomposed components of the gtest_internal_run_death_test flag,
|
||||||
// parsed when RUN_ALL_TESTS is called.
|
// parsed when RUN_ALL_TESTS is called.
|
||||||
internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
|
std::unique_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
|
||||||
internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
|
std::unique_ptr<internal::DeathTestFactory> death_test_factory_;
|
||||||
#endif // GTEST_HAS_DEATH_TEST
|
#endif // GTEST_HAS_DEATH_TEST
|
||||||
|
|
||||||
// A per-thread stack of traces created by the SCOPED_TRACE() macro.
|
// A per-thread stack of traces created by the SCOPED_TRACE() macro.
|
||||||
|
@ -976,24 +1020,11 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
|
||||||
char* end;
|
char* end;
|
||||||
// BiggestConvertible is the largest integer type that system-provided
|
// BiggestConvertible is the largest integer type that system-provided
|
||||||
// string-to-number conversion routines can return.
|
// string-to-number conversion routines can return.
|
||||||
|
using BiggestConvertible = unsigned long long; // NOLINT
|
||||||
|
|
||||||
# if GTEST_OS_WINDOWS && !defined(__GNUC__)
|
const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); // NOLINT
|
||||||
|
|
||||||
// MSVC and C++ Builder define __int64 instead of the standard long long.
|
|
||||||
typedef unsigned __int64 BiggestConvertible;
|
|
||||||
const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
|
|
||||||
|
|
||||||
# else
|
|
||||||
|
|
||||||
typedef unsigned long long BiggestConvertible; // NOLINT
|
|
||||||
const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
|
|
||||||
|
|
||||||
# endif // GTEST_OS_WINDOWS && !defined(__GNUC__)
|
|
||||||
|
|
||||||
const bool parse_success = *end == '\0' && errno == 0;
|
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));
|
GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
|
||||||
|
|
||||||
const Integer result = static_cast<Integer>(parsed);
|
const Integer result = static_cast<Integer>(parsed);
|
||||||
|
@ -1032,7 +1063,7 @@ class TestResultAccessor {
|
||||||
#if GTEST_CAN_STREAM_RESULTS_
|
#if GTEST_CAN_STREAM_RESULTS_
|
||||||
|
|
||||||
// Streams test results to the given port on the given host machine.
|
// Streams test results to the given port on the given host machine.
|
||||||
class GTEST_API_ StreamingListener : public EmptyTestEventListener {
|
class StreamingListener : public EmptyTestEventListener {
|
||||||
public:
|
public:
|
||||||
// Abstract base class for writing strings to a socket.
|
// Abstract base class for writing strings to a socket.
|
||||||
class AbstractSocketWriter {
|
class AbstractSocketWriter {
|
||||||
|
@ -1040,37 +1071,35 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
|
||||||
virtual ~AbstractSocketWriter() {}
|
virtual ~AbstractSocketWriter() {}
|
||||||
|
|
||||||
// Sends a string to the socket.
|
// Sends a string to the socket.
|
||||||
virtual void Send(const string& message) = 0;
|
virtual void Send(const std::string& message) = 0;
|
||||||
|
|
||||||
// Closes the socket.
|
// Closes the socket.
|
||||||
virtual void CloseConnection() {}
|
virtual void CloseConnection() {}
|
||||||
|
|
||||||
// Sends a string and a newline to the socket.
|
// Sends a string and a newline to the socket.
|
||||||
void SendLn(const string& message) {
|
void SendLn(const std::string& message) { Send(message + "\n"); }
|
||||||
Send(message + "\n");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Concrete class for actually writing strings to a socket.
|
// Concrete class for actually writing strings to a socket.
|
||||||
class SocketWriter : public AbstractSocketWriter {
|
class SocketWriter : public AbstractSocketWriter {
|
||||||
public:
|
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) {
|
: sockfd_(-1), host_name_(host), port_num_(port) {
|
||||||
MakeConnection();
|
MakeConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SocketWriter() {
|
~SocketWriter() override {
|
||||||
if (sockfd_ != -1)
|
if (sockfd_ != -1)
|
||||||
CloseConnection();
|
CloseConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends a string to the socket.
|
// Sends a string to the socket.
|
||||||
virtual void Send(const string& message) {
|
void Send(const std::string& message) override {
|
||||||
GTEST_CHECK_(sockfd_ != -1)
|
GTEST_CHECK_(sockfd_ != -1)
|
||||||
<< "Send() can be called only when there is a connection.";
|
<< "Send() can be called only when there is a connection.";
|
||||||
|
|
||||||
const int len = static_cast<int>(message.length());
|
const auto len = static_cast<size_t>(message.length());
|
||||||
if (write(sockfd_, message.c_str(), len) != len) {
|
if (write(sockfd_, message.c_str(), len) != static_cast<ssize_t>(len)) {
|
||||||
GTEST_LOG_(WARNING)
|
GTEST_LOG_(WARNING)
|
||||||
<< "stream_result_to: failed to stream to "
|
<< "stream_result_to: failed to stream to "
|
||||||
<< host_name_ << ":" << port_num_;
|
<< host_name_ << ":" << port_num_;
|
||||||
|
@ -1082,7 +1111,7 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
|
||||||
void MakeConnection();
|
void MakeConnection();
|
||||||
|
|
||||||
// Closes the socket.
|
// Closes the socket.
|
||||||
void CloseConnection() {
|
void CloseConnection() override {
|
||||||
GTEST_CHECK_(sockfd_ != -1)
|
GTEST_CHECK_(sockfd_ != -1)
|
||||||
<< "CloseConnection() can be called only when there is a connection.";
|
<< "CloseConnection() can be called only when there is a connection.";
|
||||||
|
|
||||||
|
@ -1091,26 +1120,28 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
int sockfd_; // socket file descriptor
|
int sockfd_; // socket file descriptor
|
||||||
const string host_name_;
|
const std::string host_name_;
|
||||||
const string port_num_;
|
const std::string port_num_;
|
||||||
|
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter);
|
||||||
}; // class SocketWriter
|
}; // class SocketWriter
|
||||||
|
|
||||||
// Escapes '=', '&', '%', and '\n' characters in str as "%xx".
|
// 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)
|
StreamingListener(const std::string& host, const std::string& port)
|
||||||
: socket_writer_(new SocketWriter(host, port)) { Start(); }
|
: socket_writer_(new SocketWriter(host, port)) {
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
explicit StreamingListener(AbstractSocketWriter* socket_writer)
|
explicit StreamingListener(AbstractSocketWriter* socket_writer)
|
||||||
: socket_writer_(socket_writer) { Start(); }
|
: socket_writer_(socket_writer) { Start(); }
|
||||||
|
|
||||||
void OnTestProgramStart(const UnitTest& /* unit_test */) {
|
void OnTestProgramStart(const UnitTest& /* unit_test */) override {
|
||||||
SendLn("event=TestProgramStart");
|
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
|
// Note that Google Test current only report elapsed time for each
|
||||||
// test iteration, not for the entire test program.
|
// test iteration, not for the entire test program.
|
||||||
SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));
|
SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));
|
||||||
|
@ -1119,42 +1150,47 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
|
||||||
socket_writer_->CloseConnection();
|
socket_writer_->CloseConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) {
|
void OnTestIterationStart(const UnitTest& /* unit_test */,
|
||||||
|
int iteration) override {
|
||||||
SendLn("event=TestIterationStart&iteration=" +
|
SendLn("event=TestIterationStart&iteration=" +
|
||||||
StreamableToString(iteration));
|
StreamableToString(iteration));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) {
|
void OnTestIterationEnd(const UnitTest& unit_test,
|
||||||
|
int /* iteration */) override {
|
||||||
SendLn("event=TestIterationEnd&passed=" +
|
SendLn("event=TestIterationEnd&passed=" +
|
||||||
FormatBool(unit_test.Passed()) + "&elapsed_time=" +
|
FormatBool(unit_test.Passed()) + "&elapsed_time=" +
|
||||||
StreamableToString(unit_test.elapsed_time()) + "ms");
|
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 compatibility
|
||||||
|
void OnTestCaseStart(const TestCase& test_case) override {
|
||||||
SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
|
SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnTestCaseEnd(const TestCase& test_case) {
|
// Note that "event=TestCaseEnd" is a wire format and has to remain
|
||||||
SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed())
|
// "case" for compatibility
|
||||||
+ "&elapsed_time=" + StreamableToString(test_case.elapsed_time())
|
void OnTestCaseEnd(const TestCase& test_case) override {
|
||||||
+ "ms");
|
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());
|
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=" +
|
SendLn("event=TestEnd&passed=" +
|
||||||
FormatBool((test_info.result())->Passed()) +
|
FormatBool((test_info.result())->Passed()) +
|
||||||
"&elapsed_time=" +
|
"&elapsed_time=" +
|
||||||
StreamableToString((test_info.result())->elapsed_time()) + "ms");
|
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();
|
const char* file_name = test_part_result.file_name();
|
||||||
if (file_name == NULL)
|
if (file_name == nullptr) file_name = "";
|
||||||
file_name = "";
|
|
||||||
SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
|
SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
|
||||||
"&line=" + StreamableToString(test_part_result.line_number()) +
|
"&line=" + StreamableToString(test_part_result.line_number()) +
|
||||||
"&message=" + UrlEncode(test_part_result.message()));
|
"&message=" + UrlEncode(test_part_result.message()));
|
||||||
|
@ -1162,15 +1198,15 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Sends the given message and a newline to the socket.
|
// 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
|
// Called at the start of streaming to notify the receiver what
|
||||||
// protocol we are using.
|
// protocol we are using.
|
||||||
void Start() { SendLn("gtest_streaming_protocol_version=1.0"); }
|
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<AbstractSocketWriter> socket_writer_;
|
const std::unique_ptr<AbstractSocketWriter> socket_writer_;
|
||||||
|
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
|
||||||
}; // class StreamingListener
|
}; // class StreamingListener
|
||||||
|
@ -1180,4 +1216,6 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener {
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_
|
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
|
||||||
|
|
||||||
|
#endif // GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
|
||||||
|
|
|
@ -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 <string>
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
// Constructs a matcher that matches a const std::string& whose value is
|
||||||
|
// equal to s.
|
||||||
|
Matcher<const std::string&>::Matcher(const std::string& s) { *this = Eq(s); }
|
||||||
|
|
||||||
|
// Constructs a matcher that matches a const std::string& whose value is
|
||||||
|
// equal to s.
|
||||||
|
Matcher<const std::string&>::Matcher(const char* s) {
|
||||||
|
*this = Eq(std::string(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a matcher that matches a std::string whose value is equal to
|
||||||
|
// s.
|
||||||
|
Matcher<std::string>::Matcher(const std::string& s) { *this = Eq(s); }
|
||||||
|
|
||||||
|
// Constructs a matcher that matches a std::string whose value is equal to
|
||||||
|
// s.
|
||||||
|
Matcher<std::string>::Matcher(const char* s) { *this = Eq(std::string(s)); }
|
||||||
|
|
||||||
|
#if GTEST_INTERNAL_HAS_STRING_VIEW
|
||||||
|
// Constructs a matcher that matches a const StringView& whose value is
|
||||||
|
// equal to s.
|
||||||
|
Matcher<const internal::StringView&>::Matcher(const std::string& s) {
|
||||||
|
*this = Eq(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a matcher that matches a const StringView& whose value is
|
||||||
|
// equal to s.
|
||||||
|
Matcher<const internal::StringView&>::Matcher(const char* s) {
|
||||||
|
*this = Eq(std::string(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a matcher that matches a const StringView& whose value is
|
||||||
|
// equal to s.
|
||||||
|
Matcher<const internal::StringView&>::Matcher(internal::StringView s) {
|
||||||
|
*this = Eq(std::string(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a matcher that matches a StringView whose value is equal to
|
||||||
|
// s.
|
||||||
|
Matcher<internal::StringView>::Matcher(const std::string& s) { *this = Eq(s); }
|
||||||
|
|
||||||
|
// Constructs a matcher that matches a StringView whose value is equal to
|
||||||
|
// s.
|
||||||
|
Matcher<internal::StringView>::Matcher(const char* s) {
|
||||||
|
*this = Eq(std::string(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a matcher that matches a StringView whose value is equal to
|
||||||
|
// s.
|
||||||
|
Matcher<internal::StringView>::Matcher(internal::StringView s) {
|
||||||
|
*this = Eq(std::string(s));
|
||||||
|
}
|
||||||
|
#endif // GTEST_INTERNAL_HAS_STRING_VIEW
|
||||||
|
|
||||||
|
} // namespace testing
|
|
@ -26,22 +26,26 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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 "gtest/internal/gtest-port.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <cstdint>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#if GTEST_OS_WINDOWS
|
#if GTEST_OS_WINDOWS
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
# include <map> // Used in ThreadLocal.
|
# include <map> // Used in ThreadLocal.
|
||||||
|
# ifdef _MSC_VER
|
||||||
|
# include <crtdbg.h>
|
||||||
|
# endif // _MSC_VER
|
||||||
#else
|
#else
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif // GTEST_OS_WINDOWS
|
#endif // GTEST_OS_WINDOWS
|
||||||
|
@ -52,6 +56,14 @@
|
||||||
# include <mach/vm_map.h>
|
# include <mach/vm_map.h>
|
||||||
#endif // GTEST_OS_MAC
|
#endif // GTEST_OS_MAC
|
||||||
|
|
||||||
|
#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \
|
||||||
|
GTEST_OS_NETBSD || GTEST_OS_OPENBSD
|
||||||
|
# include <sys/sysctl.h>
|
||||||
|
# if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD
|
||||||
|
# include <sys/user.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if GTEST_OS_QNX
|
#if GTEST_OS_QNX
|
||||||
# include <devctl.h>
|
# include <devctl.h>
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
|
@ -63,19 +75,16 @@
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
#endif // GTEST_OS_AIX
|
#endif // GTEST_OS_AIX
|
||||||
|
|
||||||
|
#if GTEST_OS_FUCHSIA
|
||||||
|
# include <zircon/process.h>
|
||||||
|
# include <zircon/syscalls.h>
|
||||||
|
#endif // GTEST_OS_FUCHSIA
|
||||||
|
|
||||||
#include "gtest/gtest-spi.h"
|
#include "gtest/gtest-spi.h"
|
||||||
#include "gtest/gtest-message.h"
|
#include "gtest/gtest-message.h"
|
||||||
#include "gtest/internal/gtest-internal.h"
|
#include "gtest/internal/gtest-internal.h"
|
||||||
#include "gtest/internal/gtest-string.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 exists to
|
|
||||||
// prevent the accidental inclusion of gtest-internal-inl.h in the
|
|
||||||
// user's code.
|
|
||||||
#define GTEST_IMPLEMENTATION_ 1
|
|
||||||
#include "src/gtest-internal-inl.h"
|
#include "src/gtest-internal-inl.h"
|
||||||
#undef GTEST_IMPLEMENTATION_
|
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -93,7 +102,7 @@ const int kStdErrFileno = STDERR_FILENO;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T ReadProcFileField(const string& filename, int field) {
|
T ReadProcFileField(const std::string& filename, int field) {
|
||||||
std::string dummy;
|
std::string dummy;
|
||||||
std::ifstream file(filename.c_str());
|
std::ifstream file(filename.c_str());
|
||||||
while (field-- > 0) {
|
while (field-- > 0) {
|
||||||
|
@ -107,9 +116,9 @@ T ReadProcFileField(const string& filename, int field) {
|
||||||
|
|
||||||
// Returns the number of active threads, or 0 when there is an error.
|
// Returns the number of active threads, or 0 when there is an error.
|
||||||
size_t GetThreadCount() {
|
size_t GetThreadCount() {
|
||||||
const string filename =
|
const std::string filename =
|
||||||
(Message() << "/proc/" << getpid() << "/stat").GetString();
|
(Message() << "/proc/" << getpid() << "/stat").GetString();
|
||||||
return ReadProcFileField<int>(filename, 19);
|
return ReadProcFileField<size_t>(filename, 19);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif GTEST_OS_MAC
|
#elif GTEST_OS_MAC
|
||||||
|
@ -131,6 +140,82 @@ 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<size_t>(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] = static_cast<int>(size / static_cast<size_t>(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
|
||||||
|
size_t nthreads = 0;
|
||||||
|
for (size_t i = 0; i < size / static_cast<size_t>(mib[4]); i++) {
|
||||||
|
if (info[i].p_tid != -1)
|
||||||
|
nthreads++;
|
||||||
|
}
|
||||||
|
return nthreads;
|
||||||
|
}
|
||||||
|
|
||||||
#elif GTEST_OS_QNX
|
#elif GTEST_OS_QNX
|
||||||
|
|
||||||
// Returns the number of threads running in the process, or 0 to indicate that
|
// Returns the number of threads running in the process, or 0 to indicate that
|
||||||
|
@ -142,7 +227,7 @@ size_t GetThreadCount() {
|
||||||
}
|
}
|
||||||
procfs_info process_info;
|
procfs_info process_info;
|
||||||
const int status =
|
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);
|
close(fd);
|
||||||
if (status == EOK) {
|
if (status == EOK) {
|
||||||
return static_cast<size_t>(process_info.num_threads);
|
return static_cast<size_t>(process_info.num_threads);
|
||||||
|
@ -156,7 +241,7 @@ size_t GetThreadCount() {
|
||||||
size_t GetThreadCount() {
|
size_t GetThreadCount() {
|
||||||
struct procentry64 entry;
|
struct procentry64 entry;
|
||||||
pid_t pid = getpid();
|
pid_t pid = getpid();
|
||||||
int status = getprocs64(&entry, sizeof(entry), NULL, 0, &pid, 1);
|
int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1);
|
||||||
if (status == 1) {
|
if (status == 1) {
|
||||||
return entry.pi_thcount;
|
return entry.pi_thcount;
|
||||||
} else {
|
} else {
|
||||||
|
@ -164,6 +249,25 @@ size_t GetThreadCount() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
#else
|
||||||
|
|
||||||
size_t GetThreadCount() {
|
size_t GetThreadCount() {
|
||||||
|
@ -177,7 +281,7 @@ size_t GetThreadCount() {
|
||||||
#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
|
#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
|
||||||
|
|
||||||
void SleepMilliseconds(int n) {
|
void SleepMilliseconds(int n) {
|
||||||
::Sleep(n);
|
::Sleep(static_cast<DWORD>(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoHandle::AutoHandle()
|
AutoHandle::AutoHandle()
|
||||||
|
@ -215,15 +319,15 @@ void AutoHandle::Reset(HANDLE handle) {
|
||||||
bool AutoHandle::IsCloseable() const {
|
bool AutoHandle::IsCloseable() const {
|
||||||
// Different Windows APIs may use either of these values to represent an
|
// Different Windows APIs may use either of these values to represent an
|
||||||
// invalid handle.
|
// invalid handle.
|
||||||
return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE;
|
return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification::Notification()
|
Notification::Notification()
|
||||||
: event_(::CreateEvent(NULL, // Default security attributes.
|
: event_(::CreateEvent(nullptr, // Default security attributes.
|
||||||
TRUE, // Do not reset automatically.
|
TRUE, // Do not reset automatically.
|
||||||
FALSE, // Initially unset.
|
FALSE, // Initially unset.
|
||||||
NULL)) { // Anonymous event.
|
nullptr)) { // Anonymous event.
|
||||||
GTEST_CHECK_(event_.Get() != NULL);
|
GTEST_CHECK_(event_.Get() != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Notification::Notify() {
|
void Notification::Notify() {
|
||||||
|
@ -246,13 +350,10 @@ Mutex::Mutex()
|
||||||
Mutex::~Mutex() {
|
Mutex::~Mutex() {
|
||||||
// Static mutexes are leaked intentionally. It is not thread-safe to try
|
// Static mutexes are leaked intentionally. It is not thread-safe to try
|
||||||
// to clean them up.
|
// to clean them up.
|
||||||
// TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires
|
|
||||||
// nothing to clean it up but is available only on Vista and later.
|
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx
|
|
||||||
if (type_ == kDynamic) {
|
if (type_ == kDynamic) {
|
||||||
::DeleteCriticalSection(critical_section_);
|
::DeleteCriticalSection(critical_section_);
|
||||||
delete critical_section_;
|
delete critical_section_;
|
||||||
critical_section_ = NULL;
|
critical_section_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +380,41 @@ void Mutex::AssertHeld() {
|
||||||
<< "The current thread is not holding the mutex @" << this;
|
<< "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.
|
// Initializes owner_thread_id_ and critical_section_ in static mutexes.
|
||||||
void Mutex::ThreadSafeLazyInit() {
|
void Mutex::ThreadSafeLazyInit() {
|
||||||
// Dynamic mutexes are initialized in the constructor.
|
// Dynamic mutexes are initialized in the constructor.
|
||||||
|
@ -289,7 +425,13 @@ void Mutex::ThreadSafeLazyInit() {
|
||||||
// If critical_section_init_phase_ was 0 before the exchange, we
|
// If critical_section_init_phase_ was 0 before the exchange, we
|
||||||
// are the first to test it and need to perform the initialization.
|
// are the first to test it and need to perform the initialization.
|
||||||
owner_thread_id_ = 0;
|
owner_thread_id_ = 0;
|
||||||
critical_section_ = new CRITICAL_SECTION;
|
{
|
||||||
|
// 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_);
|
::InitializeCriticalSection(critical_section_);
|
||||||
// Updates the critical_section_init_phase_ to 2 to signal
|
// Updates the critical_section_init_phase_ to 2 to signal
|
||||||
// initialization complete.
|
// initialization complete.
|
||||||
|
@ -328,17 +470,16 @@ class ThreadWithParamSupport : public ThreadWithParamBase {
|
||||||
Notification* thread_can_start) {
|
Notification* thread_can_start) {
|
||||||
ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start);
|
ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start);
|
||||||
DWORD thread_id;
|
DWORD thread_id;
|
||||||
// TODO(yukawa): Consider to use _beginthreadex instead.
|
|
||||||
HANDLE thread_handle = ::CreateThread(
|
HANDLE thread_handle = ::CreateThread(
|
||||||
NULL, // Default security.
|
nullptr, // Default security.
|
||||||
0, // Default stack size.
|
0, // Default stack size.
|
||||||
&ThreadWithParamSupport::ThreadMain,
|
&ThreadWithParamSupport::ThreadMain,
|
||||||
param, // Parameter to ThreadMainStatic
|
param, // Parameter to ThreadMainStatic
|
||||||
0x0, // Default creation flags.
|
0x0, // Default creation flags.
|
||||||
&thread_id); // Need a valid pointer for the call to work under Win98.
|
&thread_id); // Need a valid pointer for the call to work under Win98.
|
||||||
GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error "
|
GTEST_CHECK_(thread_handle != nullptr)
|
||||||
<< ::GetLastError() << ".";
|
<< "CreateThread failed with error " << ::GetLastError() << ".";
|
||||||
if (thread_handle == NULL) {
|
if (thread_handle == nullptr) {
|
||||||
delete param;
|
delete param;
|
||||||
}
|
}
|
||||||
return thread_handle;
|
return thread_handle;
|
||||||
|
@ -350,15 +491,15 @@ class ThreadWithParamSupport : public ThreadWithParamBase {
|
||||||
: runnable_(runnable),
|
: runnable_(runnable),
|
||||||
thread_can_start_(thread_can_start) {
|
thread_can_start_(thread_can_start) {
|
||||||
}
|
}
|
||||||
scoped_ptr<Runnable> runnable_;
|
std::unique_ptr<Runnable> runnable_;
|
||||||
// Does not own.
|
// Does not own.
|
||||||
Notification* thread_can_start_;
|
Notification* thread_can_start_;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DWORD WINAPI ThreadMain(void* ptr) {
|
static DWORD WINAPI ThreadMain(void* ptr) {
|
||||||
// Transfers ownership.
|
// Transfers ownership.
|
||||||
scoped_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr));
|
std::unique_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr));
|
||||||
if (param->thread_can_start_ != NULL)
|
if (param->thread_can_start_ != nullptr)
|
||||||
param->thread_can_start_->WaitForNotification();
|
param->thread_can_start_->WaitForNotification();
|
||||||
param->runnable_->Run();
|
param->runnable_->Run();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -397,6 +538,9 @@ class ThreadLocalRegistryImpl {
|
||||||
// Returns a value that can be used to identify the thread from other threads.
|
// Returns a value that can be used to identify the thread from other threads.
|
||||||
static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
|
static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
|
||||||
const ThreadLocalBase* thread_local_instance) {
|
const ThreadLocalBase* thread_local_instance) {
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
MemoryIsNotDeallocated memory_is_not_deallocated;
|
||||||
|
#endif // _MSC_VER
|
||||||
DWORD current_thread = ::GetCurrentThreadId();
|
DWORD current_thread = ::GetCurrentThreadId();
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
ThreadIdToThreadLocals* const thread_to_thread_locals =
|
ThreadIdToThreadLocals* const thread_to_thread_locals =
|
||||||
|
@ -416,7 +560,7 @@ class ThreadLocalRegistryImpl {
|
||||||
thread_local_values
|
thread_local_values
|
||||||
.insert(std::make_pair(
|
.insert(std::make_pair(
|
||||||
thread_local_instance,
|
thread_local_instance,
|
||||||
linked_ptr<ThreadLocalValueHolderBase>(
|
std::shared_ptr<ThreadLocalValueHolderBase>(
|
||||||
thread_local_instance->NewValueForCurrentThread())))
|
thread_local_instance->NewValueForCurrentThread())))
|
||||||
.first;
|
.first;
|
||||||
}
|
}
|
||||||
|
@ -425,7 +569,7 @@ class ThreadLocalRegistryImpl {
|
||||||
|
|
||||||
static void OnThreadLocalDestroyed(
|
static void OnThreadLocalDestroyed(
|
||||||
const ThreadLocalBase* thread_local_instance) {
|
const ThreadLocalBase* thread_local_instance) {
|
||||||
std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
|
std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
|
||||||
// Clean up the ThreadLocalValues data structure while holding the lock, but
|
// Clean up the ThreadLocalValues data structure while holding the lock, but
|
||||||
// defer the destruction of the ThreadLocalValueHolderBases.
|
// defer the destruction of the ThreadLocalValueHolderBases.
|
||||||
{
|
{
|
||||||
|
@ -453,7 +597,7 @@ class ThreadLocalRegistryImpl {
|
||||||
|
|
||||||
static void OnThreadExit(DWORD thread_id) {
|
static void OnThreadExit(DWORD thread_id) {
|
||||||
GTEST_CHECK_(thread_id != 0) << ::GetLastError();
|
GTEST_CHECK_(thread_id != 0) << ::GetLastError();
|
||||||
std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
|
std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
|
||||||
// Clean up the ThreadIdToThreadLocals data structure while holding the
|
// Clean up the ThreadIdToThreadLocals data structure while holding the
|
||||||
// lock, but defer the destruction of the ThreadLocalValueHolderBases.
|
// lock, but defer the destruction of the ThreadLocalValueHolderBases.
|
||||||
{
|
{
|
||||||
|
@ -480,7 +624,8 @@ class ThreadLocalRegistryImpl {
|
||||||
private:
|
private:
|
||||||
// In a particular thread, maps a ThreadLocal object to its value.
|
// In a particular thread, maps a ThreadLocal object to its value.
|
||||||
typedef std::map<const ThreadLocalBase*,
|
typedef std::map<const ThreadLocalBase*,
|
||||||
linked_ptr<ThreadLocalValueHolderBase> > ThreadLocalValues;
|
std::shared_ptr<ThreadLocalValueHolderBase> >
|
||||||
|
ThreadLocalValues;
|
||||||
// Stores all ThreadIdToThreadLocals having values in a thread, indexed by
|
// Stores all ThreadIdToThreadLocals having values in a thread, indexed by
|
||||||
// thread's ID.
|
// thread's ID.
|
||||||
typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals;
|
typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals;
|
||||||
|
@ -495,18 +640,17 @@ class ThreadLocalRegistryImpl {
|
||||||
HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
|
HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
|
||||||
FALSE,
|
FALSE,
|
||||||
thread_id);
|
thread_id);
|
||||||
GTEST_CHECK_(thread != NULL);
|
GTEST_CHECK_(thread != nullptr);
|
||||||
// We need to to pass a valid thread ID pointer into CreateThread for it
|
// We need to pass a valid thread ID pointer into CreateThread for it
|
||||||
// to work correctly under Win98.
|
// to work correctly under Win98.
|
||||||
DWORD watcher_thread_id;
|
DWORD watcher_thread_id;
|
||||||
HANDLE watcher_thread = ::CreateThread(
|
HANDLE watcher_thread = ::CreateThread(
|
||||||
NULL, // Default security.
|
nullptr, // Default security.
|
||||||
0, // Default stack size
|
0, // Default stack size
|
||||||
&ThreadLocalRegistryImpl::WatcherThreadFunc,
|
&ThreadLocalRegistryImpl::WatcherThreadFunc,
|
||||||
reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)),
|
reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)),
|
||||||
CREATE_SUSPENDED,
|
CREATE_SUSPENDED, &watcher_thread_id);
|
||||||
&watcher_thread_id);
|
GTEST_CHECK_(watcher_thread != nullptr);
|
||||||
GTEST_CHECK_(watcher_thread != NULL);
|
|
||||||
// Give the watcher thread the same priority as ours to avoid being
|
// Give the watcher thread the same priority as ours to avoid being
|
||||||
// blocked by it.
|
// blocked by it.
|
||||||
::SetThreadPriority(watcher_thread,
|
::SetThreadPriority(watcher_thread,
|
||||||
|
@ -531,7 +675,10 @@ class ThreadLocalRegistryImpl {
|
||||||
// Returns map of thread local instances.
|
// Returns map of thread local instances.
|
||||||
static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
|
static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
|
||||||
mutex_.AssertHeld();
|
mutex_.AssertHeld();
|
||||||
static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals;
|
#ifdef _MSC_VER
|
||||||
|
MemoryIsNotDeallocated memory_is_not_deallocated;
|
||||||
|
#endif // _MSC_VER
|
||||||
|
static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals();
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,8 +688,8 @@ class ThreadLocalRegistryImpl {
|
||||||
static Mutex thread_map_mutex_;
|
static Mutex thread_map_mutex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex);
|
Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); // NOLINT
|
||||||
Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex);
|
Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); // NOLINT
|
||||||
|
|
||||||
ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread(
|
ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread(
|
||||||
const ThreadLocalBase* thread_local_instance) {
|
const ThreadLocalBase* thread_local_instance) {
|
||||||
|
@ -573,7 +720,7 @@ RE::~RE() {
|
||||||
free(const_cast<char*>(pattern_));
|
free(const_cast<char*>(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) {
|
bool RE::FullMatch(const char* str, const RE& re) {
|
||||||
if (!re.is_valid_) return false;
|
if (!re.is_valid_) return false;
|
||||||
|
|
||||||
|
@ -581,8 +728,8 @@ bool RE::FullMatch(const char* str, const RE& re) {
|
||||||
return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
|
return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff regular expression re matches a substring of str
|
// Returns true if and only if regular expression re matches a substring of
|
||||||
// (including str itself).
|
// str (including str itself).
|
||||||
bool RE::PartialMatch(const char* str, const RE& re) {
|
bool RE::PartialMatch(const char* str, const RE& re) {
|
||||||
if (!re.is_valid_) return false;
|
if (!re.is_valid_) return false;
|
||||||
|
|
||||||
|
@ -622,14 +769,14 @@ void RE::Init(const char* regex) {
|
||||||
|
|
||||||
#elif GTEST_USES_SIMPLE_RE
|
#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).
|
// terminating '\0' character).
|
||||||
bool IsInSet(char ch, const char* str) {
|
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
|
// Returns true if and only if ch belongs to the given classification.
|
||||||
// similar functions in <ctype.h>, these aren't affected by the
|
// Unlike similar functions in <ctype.h>, these aren't affected by the
|
||||||
// current locale.
|
// current locale.
|
||||||
bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
|
bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
|
||||||
bool IsAsciiPunct(char ch) {
|
bool IsAsciiPunct(char ch) {
|
||||||
|
@ -642,13 +789,13 @@ bool IsAsciiWordChar(char ch) {
|
||||||
('0' <= ch && ch <= '9') || 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) {
|
bool IsValidEscape(char c) {
|
||||||
return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
|
return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff the given atom (specified by escaped and pattern)
|
// Returns true if and only if the given atom (specified by escaped and
|
||||||
// matches ch. The result is undefined if the atom is invalid.
|
// pattern) matches ch. The result is undefined if the atom is invalid.
|
||||||
bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
|
bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
|
||||||
if (escaped) { // "\\p" where p is pattern_char.
|
if (escaped) { // "\\p" where p is pattern_char.
|
||||||
switch (pattern_char) {
|
switch (pattern_char) {
|
||||||
|
@ -671,7 +818,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function used by ValidateRegex() to format error messages.
|
// 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
|
return (Message() << "Syntax error at index " << index
|
||||||
<< " in simple regular expression \"" << regex << "\": ").GetString();
|
<< " in simple regular expression \"" << regex << "\": ").GetString();
|
||||||
}
|
}
|
||||||
|
@ -679,17 +826,14 @@ std::string FormatRegexSyntaxError(const char* regex, int index) {
|
||||||
// Generates non-fatal failures and returns false if regex is invalid;
|
// Generates non-fatal failures and returns false if regex is invalid;
|
||||||
// otherwise returns true.
|
// otherwise returns true.
|
||||||
bool ValidateRegex(const char* regex) {
|
bool ValidateRegex(const char* regex) {
|
||||||
if (regex == NULL) {
|
if (regex == nullptr) {
|
||||||
// TODO(wan@google.com): fix the source file location in the
|
|
||||||
// assertion failures to match where the regex is used in user
|
|
||||||
// code.
|
|
||||||
ADD_FAILURE() << "NULL is not a valid simple regular expression.";
|
ADD_FAILURE() << "NULL is not a valid simple regular expression.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_valid = true;
|
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;
|
bool prev_repeatable = false;
|
||||||
for (int i = 0; regex[i]; i++) {
|
for (int i = 0; regex[i]; i++) {
|
||||||
if (regex[i] == '\\') { // An escape sequence
|
if (regex[i] == '\\') { // An escape sequence
|
||||||
|
@ -765,8 +909,8 @@ bool MatchRepetitionAndRegexAtHead(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff regex matches a prefix of str. regex must be a
|
// Returns true if and only if regex matches a prefix of str. regex must
|
||||||
// valid simple regular expression and not start with "^", or the
|
// be a valid simple regular expression and not start with "^", or the
|
||||||
// result is undefined.
|
// result is undefined.
|
||||||
bool MatchRegexAtHead(const char* regex, const char* str) {
|
bool MatchRegexAtHead(const char* regex, const char* str) {
|
||||||
if (*regex == '\0') // An empty regex matches a prefix of anything.
|
if (*regex == '\0') // An empty regex matches a prefix of anything.
|
||||||
|
@ -796,8 +940,8 @@ bool MatchRegexAtHead(const char* regex, const char* str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff regex matches any substring of str. regex must be
|
// Returns true if and only if regex matches any substring of str. regex must
|
||||||
// a valid simple regular expression, or the result is undefined.
|
// be a valid simple regular expression, or the result is undefined.
|
||||||
//
|
//
|
||||||
// The algorithm is recursive, but the recursion depth doesn't exceed
|
// 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
|
// the regex length, so we won't need to worry about running out of
|
||||||
|
@ -805,8 +949,7 @@ bool MatchRegexAtHead(const char* regex, const char* str) {
|
||||||
// exponential with respect to the regex length + the string length,
|
// exponential with respect to the regex length + the string length,
|
||||||
// but usually it's must faster (often close to linear).
|
// but usually it's must faster (often close to linear).
|
||||||
bool MatchRegexAnywhere(const char* regex, const char* str) {
|
bool MatchRegexAnywhere(const char* regex, const char* str) {
|
||||||
if (regex == NULL || str == NULL)
|
if (regex == nullptr || str == nullptr) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
if (*regex == '^')
|
if (*regex == '^')
|
||||||
return MatchRegexAtHead(regex + 1, str);
|
return MatchRegexAtHead(regex + 1, str);
|
||||||
|
@ -826,21 +969,21 @@ RE::~RE() {
|
||||||
free(const_cast<char*>(full_pattern_));
|
free(const_cast<char*>(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) {
|
bool RE::FullMatch(const char* str, const RE& re) {
|
||||||
return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
|
return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff regular expression re matches a substring of str
|
// Returns true if and only if regular expression re matches a substring of
|
||||||
// (including str itself).
|
// str (including str itself).
|
||||||
bool RE::PartialMatch(const char* str, const RE& re) {
|
bool RE::PartialMatch(const char* str, const RE& re) {
|
||||||
return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
|
return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes an RE from its string representation.
|
// Initializes an RE from its string representation.
|
||||||
void RE::Init(const char* regex) {
|
void RE::Init(const char* regex) {
|
||||||
pattern_ = full_pattern_ = NULL;
|
pattern_ = full_pattern_ = nullptr;
|
||||||
if (regex != NULL) {
|
if (regex != nullptr) {
|
||||||
pattern_ = posix::StrDup(regex);
|
pattern_ = posix::StrDup(regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,7 +1021,7 @@ const char kUnknownFile[] = "unknown file";
|
||||||
// Formats a source file path and a line number as they would appear
|
// 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.
|
// in an error message from the compiler used to compile this code.
|
||||||
GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
|
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) {
|
if (line < 0) {
|
||||||
return file_name + ":";
|
return file_name + ":";
|
||||||
|
@ -897,7 +1040,7 @@ GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
|
||||||
// to the file location it produces, unlike FormatFileLocation().
|
// to the file location it produces, unlike FormatFileLocation().
|
||||||
GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
|
GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
|
||||||
const char* file, int line) {
|
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)
|
if (line < 0)
|
||||||
return file_name;
|
return file_name;
|
||||||
|
@ -923,10 +1066,11 @@ GTestLog::~GTestLog() {
|
||||||
posix::Abort();
|
posix::Abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable Microsoft deprecation warnings for POSIX functions called from
|
// Disable Microsoft deprecation warnings for POSIX functions called from
|
||||||
// this class (creat, dup, dup2, and close)
|
// this class (creat, dup, dup2, and close)
|
||||||
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
|
GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
|
||||||
GTEST_DISABLE_CLANG_DEPRECATED_WARNINGS_PUSH_()
|
|
||||||
#if GTEST_HAS_STREAM_REDIRECTION
|
#if GTEST_HAS_STREAM_REDIRECTION
|
||||||
|
|
||||||
// Object that captures an output stream (stdout/stderr).
|
// Object that captures an output stream (stdout/stderr).
|
||||||
|
@ -951,9 +1095,9 @@ class CapturedStream {
|
||||||
filename_ = temp_file_path;
|
filename_ = temp_file_path;
|
||||||
# else
|
# else
|
||||||
// There's no guarantee that a test has write access to the current
|
// There's no guarantee that a test has write access to the current
|
||||||
// directory, so we create the temporary file in the /tmp directory
|
// directory, so we create the temporary file in a temporary directory.
|
||||||
// instead. We use /tmp on most systems, and /sdcard on Android.
|
std::string name_template;
|
||||||
// That's because Android doesn't have /tmp.
|
|
||||||
# if GTEST_OS_LINUX_ANDROID
|
# if GTEST_OS_LINUX_ANDROID
|
||||||
// Note: Android applications are expected to call the framework's
|
// Note: Android applications are expected to call the framework's
|
||||||
// Context.getExternalStorageDirectory() method through JNI to get
|
// Context.getExternalStorageDirectory() method through JNI to get
|
||||||
|
@ -963,20 +1107,51 @@ class CapturedStream {
|
||||||
// code as part of a regular standalone executable, which doesn't
|
// code as part of a regular standalone executable, which doesn't
|
||||||
// run in a Dalvik process (e.g. when running it through 'adb shell').
|
// run in a Dalvik process (e.g. when running it through 'adb shell').
|
||||||
//
|
//
|
||||||
// The location /sdcard is directly accessible from native code
|
// The location /data/local/tmp is directly accessible from native code.
|
||||||
// and is the only location (unofficially) supported by the Android
|
// '/sdcard' and other variants cannot be relied on, as they are not
|
||||||
// team. It's generally a symlink to the real SD Card mount point
|
// guaranteed to be mounted, or may have a delay in mounting.
|
||||||
// which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or
|
name_template = "/data/local/tmp/";
|
||||||
// other OEM-customized locations. Never rely on these, and always
|
# elif GTEST_OS_IOS
|
||||||
// use /sdcard.
|
char user_temp_dir[PATH_MAX + 1];
|
||||||
char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX";
|
|
||||||
|
// Documented alternative to NSTemporaryDirectory() (for obtaining creating
|
||||||
|
// a temporary directory) at
|
||||||
|
// https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10
|
||||||
|
//
|
||||||
|
// _CS_DARWIN_USER_TEMP_DIR (as well as _CS_DARWIN_USER_CACHE_DIR) is not
|
||||||
|
// documented in the confstr() man page at
|
||||||
|
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/confstr.3.html#//apple_ref/doc/man/3/confstr
|
||||||
|
// but are still available, according to the WebKit patches at
|
||||||
|
// https://trac.webkit.org/changeset/262004/webkit
|
||||||
|
// https://trac.webkit.org/changeset/263705/webkit
|
||||||
|
//
|
||||||
|
// The confstr() implementation falls back to getenv("TMPDIR"). See
|
||||||
|
// https://opensource.apple.com/source/Libc/Libc-1439.100.3/gen/confstr.c.auto.html
|
||||||
|
::confstr(_CS_DARWIN_USER_TEMP_DIR, user_temp_dir, sizeof(user_temp_dir));
|
||||||
|
|
||||||
|
name_template = user_temp_dir;
|
||||||
|
if (name_template.back() != GTEST_PATH_SEP_[0])
|
||||||
|
name_template.push_back(GTEST_PATH_SEP_[0]);
|
||||||
# else
|
# else
|
||||||
char name_template[] = "/tmp/captured_stream.XXXXXX";
|
name_template = "/tmp/";
|
||||||
# endif // GTEST_OS_LINUX_ANDROID
|
# endif
|
||||||
const int captured_fd = mkstemp(name_template);
|
name_template.append("gtest_captured_stream.XXXXXX");
|
||||||
filename_ = name_template;
|
|
||||||
|
// mkstemp() modifies the string bytes in place, and does not go beyond the
|
||||||
|
// string's length. This results in well-defined behavior in C++17.
|
||||||
|
//
|
||||||
|
// The const_cast is needed below C++17. The constraints on std::string
|
||||||
|
// implementations in C++11 and above make assumption behind the const_cast
|
||||||
|
// fairly safe.
|
||||||
|
const int captured_fd = ::mkstemp(const_cast<char*>(name_template.data()));
|
||||||
|
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_ = std::move(name_template);
|
||||||
# endif // GTEST_OS_WINDOWS
|
# endif // GTEST_OS_WINDOWS
|
||||||
fflush(NULL);
|
fflush(nullptr);
|
||||||
dup2(captured_fd, fd_);
|
dup2(captured_fd, fd_);
|
||||||
close(captured_fd);
|
close(captured_fd);
|
||||||
}
|
}
|
||||||
|
@ -988,13 +1163,17 @@ class CapturedStream {
|
||||||
std::string GetCapturedString() {
|
std::string GetCapturedString() {
|
||||||
if (uncaptured_fd_ != -1) {
|
if (uncaptured_fd_ != -1) {
|
||||||
// Restores the original stream.
|
// Restores the original stream.
|
||||||
fflush(NULL);
|
fflush(nullptr);
|
||||||
dup2(uncaptured_fd_, fd_);
|
dup2(uncaptured_fd_, fd_);
|
||||||
close(uncaptured_fd_);
|
close(uncaptured_fd_);
|
||||||
uncaptured_fd_ = -1;
|
uncaptured_fd_ = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* const file = posix::FOpen(filename_.c_str(), "r");
|
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);
|
const std::string content = ReadEntireFile(file);
|
||||||
posix::FClose(file);
|
posix::FClose(file);
|
||||||
return content;
|
return content;
|
||||||
|
@ -1009,15 +1188,15 @@ class CapturedStream {
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
|
||||||
};
|
};
|
||||||
|
|
||||||
GTEST_DISABLE_MSC_WARNINGS_POP_()
|
GTEST_DISABLE_MSC_DEPRECATED_POP_()
|
||||||
GTEST_DISABLE_CLANG_WARNINGS_POP_()
|
|
||||||
|
|
||||||
static CapturedStream* g_captured_stderr = NULL;
|
static CapturedStream* g_captured_stderr = nullptr;
|
||||||
static CapturedStream* g_captured_stdout = NULL;
|
static CapturedStream* g_captured_stdout = nullptr;
|
||||||
|
|
||||||
// Starts capturing an output stream (stdout/stderr).
|
// Starts capturing an output stream (stdout/stderr).
|
||||||
void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
|
static void CaptureStream(int fd, const char* stream_name,
|
||||||
if (*stream != NULL) {
|
CapturedStream** stream) {
|
||||||
|
if (*stream != nullptr) {
|
||||||
GTEST_LOG_(FATAL) << "Only one " << stream_name
|
GTEST_LOG_(FATAL) << "Only one " << stream_name
|
||||||
<< " capturer can exist at a time.";
|
<< " capturer can exist at a time.";
|
||||||
}
|
}
|
||||||
|
@ -1025,11 +1204,11 @@ void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stops capturing the output stream and returns the captured string.
|
// 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();
|
const std::string content = (*captured_stream)->GetCapturedString();
|
||||||
|
|
||||||
delete *captured_stream;
|
delete *captured_stream;
|
||||||
*captured_stream = NULL;
|
*captured_stream = nullptr;
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
@ -1056,23 +1235,9 @@ std::string GetCapturedStderr() {
|
||||||
|
|
||||||
#endif // GTEST_HAS_STREAM_REDIRECTION
|
#endif // GTEST_HAS_STREAM_REDIRECTION
|
||||||
|
|
||||||
std::string TempDir() {
|
|
||||||
#if GTEST_OS_WINDOWS_MOBILE
|
|
||||||
return "\\temp\\";
|
|
||||||
#elif GTEST_OS_WINDOWS
|
|
||||||
const char* temp_dir = posix::GetEnv("TEMP");
|
|
||||||
if (temp_dir == NULL || 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
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetFileSize(FILE* file) {
|
size_t GetFileSize(FILE* file) {
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
|
@ -1102,22 +1267,30 @@ std::string ReadEntireFile(FILE* file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GTEST_HAS_DEATH_TEST
|
#if GTEST_HAS_DEATH_TEST
|
||||||
|
static const std::vector<std::string>* g_injected_test_argvs =
|
||||||
|
nullptr; // Owned.
|
||||||
|
|
||||||
static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
|
std::vector<std::string> GetInjectableArgvs() {
|
||||||
NULL; // Owned.
|
if (g_injected_test_argvs != nullptr) {
|
||||||
|
|
||||||
void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) {
|
|
||||||
if (g_injected_test_argvs != argvs)
|
|
||||||
delete g_injected_test_argvs;
|
|
||||||
g_injected_test_argvs = argvs;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
|
|
||||||
if (g_injected_test_argvs != NULL) {
|
|
||||||
return *g_injected_test_argvs;
|
return *g_injected_test_argvs;
|
||||||
}
|
}
|
||||||
return GetArgvs();
|
return GetArgvs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetInjectableArgvs(const std::vector<std::string>* 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<std::string>& new_argvs) {
|
||||||
|
SetInjectableArgvs(
|
||||||
|
new std::vector<std::string>(new_argvs.begin(), new_argvs.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearInjectableArgvs() {
|
||||||
|
delete g_injected_test_argvs;
|
||||||
|
g_injected_test_argvs = nullptr;
|
||||||
|
}
|
||||||
#endif // GTEST_HAS_DEATH_TEST
|
#endif // GTEST_HAS_DEATH_TEST
|
||||||
|
|
||||||
#if GTEST_OS_WINDOWS_MOBILE
|
#if GTEST_OS_WINDOWS_MOBILE
|
||||||
|
@ -1147,9 +1320,9 @@ static std::string FlagToEnvVar(const char* flag) {
|
||||||
// Parses 'str' for a 32-bit signed integer. If successful, writes
|
// Parses 'str' for a 32-bit signed integer. If successful, writes
|
||||||
// the result to *value and returns true; otherwise leaves *value
|
// the result to *value and returns true; otherwise leaves *value
|
||||||
// unchanged and returns false.
|
// unchanged and returns false.
|
||||||
bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
|
bool ParseInt32(const Message& src_text, const char* str, int32_t* value) {
|
||||||
// Parses the environment variable as a decimal integer.
|
// Parses the environment variable as a decimal integer.
|
||||||
char* end = NULL;
|
char* end = nullptr;
|
||||||
const long long_value = strtol(str, &end, 10); // NOLINT
|
const long long_value = strtol(str, &end, 10); // NOLINT
|
||||||
|
|
||||||
// Has strtol() consumed all characters in the string?
|
// Has strtol() consumed all characters in the string?
|
||||||
|
@ -1164,13 +1337,13 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is the parsed value in the range of an Int32?
|
// Is the parsed value in the range of an int32_t?
|
||||||
const Int32 result = static_cast<Int32>(long_value);
|
const auto result = static_cast<int32_t>(long_value);
|
||||||
if (long_value == LONG_MAX || long_value == LONG_MIN ||
|
if (long_value == LONG_MAX || long_value == LONG_MIN ||
|
||||||
// The parsed value overflows as a long. (strtol() returns
|
// The parsed value overflows as a long. (strtol() returns
|
||||||
// LONG_MAX or LONG_MIN when the input overflows.)
|
// LONG_MAX or LONG_MIN when the input overflows.)
|
||||||
result != long_value
|
result != long_value
|
||||||
// The parsed value overflows as an Int32.
|
// The parsed value overflows as an int32_t.
|
||||||
) {
|
) {
|
||||||
Message msg;
|
Message msg;
|
||||||
msg << "WARNING: " << src_text
|
msg << "WARNING: " << src_text
|
||||||
|
@ -1188,32 +1361,33 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
|
||||||
// Reads and returns the Boolean environment variable corresponding to
|
// Reads and returns the Boolean environment variable corresponding to
|
||||||
// the given flag; if it's not set, returns default_value.
|
// 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) {
|
bool BoolFromGTestEnv(const char* flag, bool default_value) {
|
||||||
#if defined(GTEST_GET_BOOL_FROM_ENV_)
|
#if defined(GTEST_GET_BOOL_FROM_ENV_)
|
||||||
return GTEST_GET_BOOL_FROM_ENV_(flag, default_value);
|
return GTEST_GET_BOOL_FROM_ENV_(flag, default_value);
|
||||||
#endif // defined(GTEST_GET_BOOL_FROM_ENV_)
|
#else
|
||||||
const std::string env_var = FlagToEnvVar(flag);
|
const std::string env_var = FlagToEnvVar(flag);
|
||||||
const char* const string_value = posix::GetEnv(env_var.c_str());
|
const char* const string_value = posix::GetEnv(env_var.c_str());
|
||||||
return string_value == NULL ?
|
return string_value == nullptr ? default_value
|
||||||
default_value : strcmp(string_value, "0") != 0;
|
: strcmp(string_value, "0") != 0;
|
||||||
|
#endif // defined(GTEST_GET_BOOL_FROM_ENV_)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads and returns a 32-bit integer stored in the environment
|
// Reads and returns a 32-bit integer stored in the environment
|
||||||
// variable corresponding to the given flag; if it isn't set or
|
// variable corresponding to the given flag; if it isn't set or
|
||||||
// doesn't represent a valid 32-bit integer, returns default_value.
|
// doesn't represent a valid 32-bit integer, returns default_value.
|
||||||
Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
|
int32_t Int32FromGTestEnv(const char* flag, int32_t default_value) {
|
||||||
#if defined(GTEST_GET_INT32_FROM_ENV_)
|
#if defined(GTEST_GET_INT32_FROM_ENV_)
|
||||||
return GTEST_GET_INT32_FROM_ENV_(flag, default_value);
|
return GTEST_GET_INT32_FROM_ENV_(flag, default_value);
|
||||||
#endif // defined(GTEST_GET_INT32_FROM_ENV_)
|
#else
|
||||||
const std::string env_var = FlagToEnvVar(flag);
|
const std::string env_var = FlagToEnvVar(flag);
|
||||||
const char* const string_value = posix::GetEnv(env_var.c_str());
|
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.
|
// The environment variable is not set.
|
||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Int32 result = default_value;
|
int32_t result = default_value;
|
||||||
if (!ParseInt32(Message() << "Environment variable " << env_var,
|
if (!ParseInt32(Message() << "Environment variable " << env_var,
|
||||||
string_value, &result)) {
|
string_value, &result)) {
|
||||||
printf("The default value %s is used.\n",
|
printf("The default value %s is used.\n",
|
||||||
|
@ -1223,37 +1397,36 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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
|
// Reads and returns the string environment variable corresponding to
|
||||||
// the given flag; if it's not set, returns default_value.
|
// the given flag; if it's not set, returns default_value.
|
||||||
std::string StringFromGTestEnv(const char* flag, const char* default_value) {
|
const char* StringFromGTestEnv(const char* flag, const char* default_value) {
|
||||||
#if defined(GTEST_GET_STRING_FROM_ENV_)
|
#if defined(GTEST_GET_STRING_FROM_ENV_)
|
||||||
return GTEST_GET_STRING_FROM_ENV_(flag, default_value);
|
return GTEST_GET_STRING_FROM_ENV_(flag, default_value);
|
||||||
#endif // defined(GTEST_GET_STRING_FROM_ENV_)
|
#else
|
||||||
const std::string env_var = FlagToEnvVar(flag);
|
const std::string env_var = FlagToEnvVar(flag);
|
||||||
const char* value = posix::GetEnv(env_var.c_str());
|
const char* const value = posix::GetEnv(env_var.c_str());
|
||||||
if (value != NULL) {
|
return value == nullptr ? default_value : value;
|
||||||
return value;
|
#endif // defined(GTEST_GET_STRING_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.
|
|
||||||
//
|
|
||||||
// The net priority order after flag processing is thus:
|
|
||||||
// --gtest_output command line flag
|
|
||||||
// GTEST_OUTPUT environment variable
|
|
||||||
// XML_OUTPUT_FILE environment variable
|
|
||||||
// 'default_value'
|
|
||||||
if (strcmp(flag, "output") == 0) {
|
|
||||||
value = posix::GetEnv("XML_OUTPUT_FILE");
|
|
||||||
if (value != NULL) {
|
|
||||||
return std::string("xml:") + value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return default_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
|
@ -26,10 +26,9 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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
|
// This file implements a universal value printer that can print a
|
||||||
// value of any type T:
|
// value of any type T:
|
||||||
|
@ -43,12 +42,18 @@
|
||||||
// defines Foo.
|
// defines Foo.
|
||||||
|
|
||||||
#include "gtest/gtest-printers.h"
|
#include "gtest/gtest-printers.h"
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <cstdint>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
#include <ostream> // NOLINT
|
#include <ostream> // NOLINT
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "gtest/internal/gtest-port.h"
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
#include "src/gtest-internal-inl.h"
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
|
||||||
|
@ -59,6 +64,7 @@ using ::std::ostream;
|
||||||
// Prints a segment of bytes in the given object.
|
// Prints a segment of bytes in the given object.
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
|
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||||
|
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
||||||
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
|
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
|
||||||
size_t count, ostream* os) {
|
size_t count, ostream* os) {
|
||||||
|
@ -89,7 +95,6 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
|
||||||
// If the object size is bigger than kThreshold, we'll have to omit
|
// If the object size is bigger than kThreshold, we'll have to omit
|
||||||
// some details by printing only the first and the last kChunkSize
|
// some details by printing only the first and the last kChunkSize
|
||||||
// bytes.
|
// bytes.
|
||||||
// TODO(wan): let the user control the threshold using a flag.
|
|
||||||
if (count < kThreshold) {
|
if (count < kThreshold) {
|
||||||
PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
|
PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,9 +107,19 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
|
||||||
*os << ">";
|
*os << ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helpers for widening a character to char32_t. Since the standard does not
|
||||||
|
// specify if char / wchar_t is signed or unsigned, it is important to first
|
||||||
|
// convert it to the unsigned type of the same width before widening it to
|
||||||
|
// char32_t.
|
||||||
|
template <typename CharType>
|
||||||
|
char32_t ToChar32(CharType in) {
|
||||||
|
return static_cast<char32_t>(
|
||||||
|
static_cast<typename std::make_unsigned<CharType>::type>(in));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace internal2 {
|
namespace internal {
|
||||||
|
|
||||||
// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
|
// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
|
||||||
// given object. The delegation simplifies the implementation, which
|
// given object. The delegation simplifies the implementation, which
|
||||||
|
@ -116,14 +131,10 @@ void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
|
||||||
PrintBytesInObjectToImpl(obj_bytes, count, os);
|
PrintBytesInObjectToImpl(obj_bytes, count, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal2
|
|
||||||
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
// Depending on the value of a char (or wchar_t), we print it in one
|
// Depending on the value of a char (or wchar_t), we print it in one
|
||||||
// of three formats:
|
// of three formats:
|
||||||
// - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
|
// - 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').
|
// - as a special escape sequence (e.g. '\r', '\n').
|
||||||
enum CharFormat {
|
enum CharFormat {
|
||||||
kAsIs,
|
kAsIs,
|
||||||
|
@ -134,17 +145,15 @@ enum CharFormat {
|
||||||
// Returns true if c is a printable ASCII character. We test the
|
// Returns true if c is a printable ASCII character. We test the
|
||||||
// value of c directly instead of calling isprint(), which is buggy on
|
// value of c directly instead of calling isprint(), which is buggy on
|
||||||
// Windows Mobile.
|
// Windows Mobile.
|
||||||
inline bool IsPrintableAscii(wchar_t c) {
|
inline bool IsPrintableAscii(char32_t c) { return 0x20 <= c && c <= 0x7E; }
|
||||||
return 0x20 <= c && c <= 0x7E;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prints a wide or narrow char c as a character literal without the
|
// Prints c (of type char, char8_t, char16_t, char32_t, or wchar_t) as a
|
||||||
// quotes, escaping it when necessary; returns how c was formatted.
|
// character literal without the quotes, escaping it when necessary; returns how
|
||||||
// The template argument UnsignedChar is the unsigned version of Char,
|
// c was formatted.
|
||||||
// which is the type of c.
|
template <typename Char>
|
||||||
template <typename UnsignedChar, typename Char>
|
|
||||||
static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
|
static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
|
||||||
switch (static_cast<wchar_t>(c)) {
|
const char32_t u_c = ToChar32(c);
|
||||||
|
switch (u_c) {
|
||||||
case L'\0':
|
case L'\0':
|
||||||
*os << "\\0";
|
*os << "\\0";
|
||||||
break;
|
break;
|
||||||
|
@ -176,20 +185,22 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
|
||||||
*os << "\\v";
|
*os << "\\v";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (IsPrintableAscii(c)) {
|
if (IsPrintableAscii(u_c)) {
|
||||||
*os << static_cast<char>(c);
|
*os << static_cast<char>(c);
|
||||||
return kAsIs;
|
return kAsIs;
|
||||||
} else {
|
} else {
|
||||||
*os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
|
ostream::fmtflags flags = os->flags();
|
||||||
|
*os << "\\x" << std::hex << std::uppercase << static_cast<int>(u_c);
|
||||||
|
os->flags(flags);
|
||||||
return kHexEscape;
|
return kHexEscape;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return kSpecialEscape;
|
return kSpecialEscape;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints a wchar_t c as if it's part of a string literal, escaping it when
|
// Prints a char32_t c as if it's part of a string literal, escaping it when
|
||||||
// necessary; returns how c was formatted.
|
// necessary; returns how c was formatted.
|
||||||
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
|
static CharFormat PrintAsStringLiteralTo(char32_t c, ostream* os) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case L'\'':
|
case L'\'':
|
||||||
*os << "'";
|
*os << "'";
|
||||||
|
@ -198,26 +209,68 @@ static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
|
||||||
*os << "\\\"";
|
*os << "\\\"";
|
||||||
return kSpecialEscape;
|
return kSpecialEscape;
|
||||||
default:
|
default:
|
||||||
return PrintAsCharLiteralTo<wchar_t>(c, os);
|
return PrintAsCharLiteralTo(c, os);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char* GetCharWidthPrefix(char) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* GetCharWidthPrefix(signed char) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* GetCharWidthPrefix(unsigned char) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cpp_char8_t
|
||||||
|
static const char* GetCharWidthPrefix(char8_t) {
|
||||||
|
return "u8";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char* GetCharWidthPrefix(char16_t) {
|
||||||
|
return "u";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* GetCharWidthPrefix(char32_t) {
|
||||||
|
return "U";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* GetCharWidthPrefix(wchar_t) {
|
||||||
|
return "L";
|
||||||
|
}
|
||||||
|
|
||||||
// Prints a char c as if it's part of a string literal, escaping it when
|
// Prints a char c as if it's part of a string literal, escaping it when
|
||||||
// necessary; returns how c was formatted.
|
// necessary; returns how c was formatted.
|
||||||
static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
|
static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
|
||||||
return PrintAsStringLiteralTo(
|
return PrintAsStringLiteralTo(ToChar32(c), os);
|
||||||
static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints a wide or narrow character c and its code. '\0' is printed
|
#ifdef __cpp_char8_t
|
||||||
// as "'\\0'", other unprintable characters are also properly escaped
|
static CharFormat PrintAsStringLiteralTo(char8_t c, ostream* os) {
|
||||||
// using the standard C++ escape sequence. The template argument
|
return PrintAsStringLiteralTo(ToChar32(c), os);
|
||||||
// UnsignedChar is the unsigned version of Char, which is the type of c.
|
}
|
||||||
template <typename UnsignedChar, typename Char>
|
#endif
|
||||||
|
|
||||||
|
static CharFormat PrintAsStringLiteralTo(char16_t c, ostream* os) {
|
||||||
|
return PrintAsStringLiteralTo(ToChar32(c), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
|
||||||
|
return PrintAsStringLiteralTo(ToChar32(c), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a character c (of type char, char8_t, char16_t, char32_t, or wchar_t)
|
||||||
|
// and its code. '\0' is printed as "'\\0'", other unprintable characters are
|
||||||
|
// also properly escaped using the standard C++ escape sequence.
|
||||||
|
template <typename Char>
|
||||||
void PrintCharAndCodeTo(Char c, ostream* os) {
|
void PrintCharAndCodeTo(Char c, ostream* os) {
|
||||||
// First, print c as a literal in the most readable form we can find.
|
// First, print c as a literal in the most readable form we can find.
|
||||||
*os << ((sizeof(c) > 1) ? "L'" : "'");
|
*os << GetCharWidthPrefix(c) << "'";
|
||||||
const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
|
const CharFormat format = PrintAsCharLiteralTo(c, os);
|
||||||
*os << "'";
|
*os << "'";
|
||||||
|
|
||||||
// To aid user debugging, we also print c's code in decimal, unless
|
// To aid user debugging, we also print c's code in decimal, unless
|
||||||
|
@ -227,54 +280,61 @@ void PrintCharAndCodeTo(Char c, ostream* os) {
|
||||||
return;
|
return;
|
||||||
*os << " (" << static_cast<int>(c);
|
*os << " (" << static_cast<int>(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
|
// unless c was already printed in the form '\x##' or the code is in
|
||||||
// [1, 9].
|
// [1, 9].
|
||||||
if (format == kHexEscape || (1 <= c && c <= 9)) {
|
if (format == kHexEscape || (1 <= c && c <= 9)) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
} else {
|
} else {
|
||||||
*os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
|
*os << ", 0x" << String::FormatHexInt(static_cast<int>(c));
|
||||||
}
|
}
|
||||||
*os << ")";
|
*os << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintTo(unsigned char c, ::std::ostream* os) {
|
void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
|
||||||
PrintCharAndCodeTo<unsigned char>(c, os);
|
void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
|
||||||
}
|
|
||||||
void PrintTo(signed char c, ::std::ostream* os) {
|
|
||||||
PrintCharAndCodeTo<unsigned char>(c, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prints a wchar_t as a symbol if it is printable or as its internal
|
// Prints a wchar_t as a symbol if it is printable or as its internal
|
||||||
// code otherwise and also as its code. L'\0' is printed as "L'\\0'".
|
// code otherwise and also as its code. L'\0' is printed as "L'\\0'".
|
||||||
void PrintTo(wchar_t wc, ostream* os) {
|
void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); }
|
||||||
PrintCharAndCodeTo<wchar_t>(wc, os);
|
|
||||||
|
// TODO(dcheng): Consider making this delegate to PrintCharAndCodeTo() as well.
|
||||||
|
void PrintTo(char32_t c, ::std::ostream* os) {
|
||||||
|
*os << std::hex << "U+" << std::uppercase << std::setfill('0') << std::setw(4)
|
||||||
|
<< static_cast<uint32_t>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints the given array of characters to the ostream. CharType must be either
|
// Prints the given array of characters to the ostream. CharType must be either
|
||||||
// char or wchar_t.
|
// char, char8_t, char16_t, char32_t, or wchar_t.
|
||||||
// The array starts at begin, the length is len, it may include '\0' characters
|
// The array starts at begin, the length is len, it may include '\0' characters
|
||||||
// and may not be NUL-terminated.
|
// and may not be NUL-terminated.
|
||||||
template <typename CharType>
|
template <typename CharType>
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
|
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||||
|
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
||||||
static void PrintCharsAsStringTo(
|
static CharFormat PrintCharsAsStringTo(
|
||||||
const CharType* begin, size_t len, ostream* os) {
|
const CharType* begin, size_t len, ostream* os) {
|
||||||
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
|
const char* const quote_prefix = GetCharWidthPrefix(*begin);
|
||||||
*os << kQuoteBegin;
|
*os << quote_prefix << "\"";
|
||||||
bool is_previous_hex = false;
|
bool is_previous_hex = false;
|
||||||
|
CharFormat print_format = kAsIs;
|
||||||
for (size_t index = 0; index < len; ++index) {
|
for (size_t index = 0; index < len; ++index) {
|
||||||
const CharType cur = begin[index];
|
const CharType cur = begin[index];
|
||||||
if (is_previous_hex && IsXDigit(cur)) {
|
if (is_previous_hex && IsXDigit(cur)) {
|
||||||
// Previous character is of '\x..' form and this character can be
|
// Previous character is of '\x..' form and this character can be
|
||||||
// interpreted as another hexadecimal digit in its number. Break string to
|
// interpreted as another hexadecimal digit in its number. Break string to
|
||||||
// disambiguate.
|
// disambiguate.
|
||||||
*os << "\" " << kQuoteBegin;
|
*os << "\" " << quote_prefix << "\"";
|
||||||
}
|
}
|
||||||
is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
|
is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
|
||||||
|
// Remember if any characters required hex escaping.
|
||||||
|
if (is_previous_hex) {
|
||||||
|
print_format = kHexEscape;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*os << "\"";
|
*os << "\"";
|
||||||
|
return print_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints a (const) char/wchar_t array of 'len' elements, starting at address
|
// Prints a (const) char/wchar_t array of 'len' elements, starting at address
|
||||||
|
@ -282,6 +342,7 @@ static void PrintCharsAsStringTo(
|
||||||
template <typename CharType>
|
template <typename CharType>
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
|
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||||
|
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
||||||
static void UniversalPrintCharArray(
|
static void UniversalPrintCharArray(
|
||||||
const CharType* begin, size_t len, ostream* os) {
|
const CharType* begin, size_t len, ostream* os) {
|
||||||
|
@ -310,22 +371,57 @@ void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
|
||||||
UniversalPrintCharArray(begin, len, os);
|
UniversalPrintCharArray(begin, len, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cpp_char8_t
|
||||||
|
// Prints a (const) char8_t array of 'len' elements, starting at address
|
||||||
|
// 'begin'.
|
||||||
|
void UniversalPrintArray(const char8_t* begin, size_t len, ostream* os) {
|
||||||
|
UniversalPrintCharArray(begin, len, os);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Prints a (const) char16_t array of 'len' elements, starting at address
|
||||||
|
// 'begin'.
|
||||||
|
void UniversalPrintArray(const char16_t* begin, size_t len, ostream* os) {
|
||||||
|
UniversalPrintCharArray(begin, len, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a (const) char32_t array of 'len' elements, starting at address
|
||||||
|
// 'begin'.
|
||||||
|
void UniversalPrintArray(const char32_t* begin, size_t len, ostream* os) {
|
||||||
|
UniversalPrintCharArray(begin, len, os);
|
||||||
|
}
|
||||||
|
|
||||||
// Prints a (const) wchar_t array of 'len' elements, starting at address
|
// Prints a (const) wchar_t array of 'len' elements, starting at address
|
||||||
// 'begin'.
|
// 'begin'.
|
||||||
void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
|
void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
|
||||||
UniversalPrintCharArray(begin, len, os);
|
UniversalPrintCharArray(begin, len, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints the given C string to the ostream.
|
namespace {
|
||||||
void PrintTo(const char* s, ostream* os) {
|
|
||||||
if (s == NULL) {
|
// Prints a null-terminated C-style string to the ostream.
|
||||||
|
template <typename Char>
|
||||||
|
void PrintCStringTo(const Char* s, ostream* os) {
|
||||||
|
if (s == nullptr) {
|
||||||
*os << "NULL";
|
*os << "NULL";
|
||||||
} else {
|
} else {
|
||||||
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
||||||
PrintCharsAsStringTo(s, strlen(s), os);
|
PrintCharsAsStringTo(s, std::char_traits<Char>::length(s), os);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
void PrintTo(const char* s, ostream* os) { PrintCStringTo(s, os); }
|
||||||
|
|
||||||
|
#ifdef __cpp_char8_t
|
||||||
|
void PrintTo(const char8_t* s, ostream* os) { PrintCStringTo(s, os); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PrintTo(const char16_t* s, ostream* os) { PrintCStringTo(s, os); }
|
||||||
|
|
||||||
|
void PrintTo(const char32_t* s, ostream* os) { PrintCStringTo(s, os); }
|
||||||
|
|
||||||
// MSVC compiler can be configured to define whar_t as a typedef
|
// MSVC compiler can be configured to define whar_t as a typedef
|
||||||
// of unsigned short. Defining an overload for const wchar_t* in that case
|
// of unsigned short. Defining an overload for const wchar_t* in that case
|
||||||
// would cause pointers to unsigned shorts be printed as wide strings,
|
// would cause pointers to unsigned shorts be printed as wide strings,
|
||||||
|
@ -334,33 +430,97 @@ void PrintTo(const char* s, ostream* os) {
|
||||||
// wchar_t is implemented as a native type.
|
// wchar_t is implemented as a native type.
|
||||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||||
// Prints the given wide C string to the ostream.
|
// Prints the given wide C string to the ostream.
|
||||||
void PrintTo(const wchar_t* s, ostream* os) {
|
void PrintTo(const wchar_t* s, ostream* os) { PrintCStringTo(s, os); }
|
||||||
if (s == NULL) {
|
|
||||||
*os << "NULL";
|
|
||||||
} else {
|
|
||||||
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
|
||||||
PrintCharsAsStringTo(s, std::wcslen(s), os);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // wchar_t is native
|
#endif // wchar_t is native
|
||||||
|
|
||||||
// Prints a ::string object.
|
namespace {
|
||||||
#if GTEST_HAS_GLOBAL_STRING
|
|
||||||
void PrintStringTo(const ::string& s, ostream* os) {
|
bool ContainsUnprintableControlCodes(const char* str, size_t length) {
|
||||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
const unsigned char *s = reinterpret_cast<const unsigned char *>(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
|
|
||||||
|
bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; }
|
||||||
|
|
||||||
|
bool IsValidUTF8(const char* str, size_t length) {
|
||||||
|
const unsigned char *s = reinterpret_cast<const unsigned char *>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cpp_char8_t
|
||||||
|
void PrintU8StringTo(const ::std::u8string& s, ostream* os) {
|
||||||
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PrintU16StringTo(const ::std::u16string& s, ostream* os) {
|
||||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints a ::wstring object.
|
void PrintU32StringTo(const ::std::u32string& s, ostream* os) {
|
||||||
#if GTEST_HAS_GLOBAL_WSTRING
|
|
||||||
void PrintWideStringTo(const ::wstring& s, ostream* os) {
|
|
||||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
}
|
}
|
||||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
|
||||||
|
|
||||||
#if GTEST_HAS_STD_WSTRING
|
#if GTEST_HAS_STD_WSTRING
|
||||||
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
|
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
|
||||||
|
|
|
@ -26,21 +26,14 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
//
|
//
|
||||||
// Author: mheule@google.com (Markus Heule)
|
// The Google C++ Testing and Mocking Framework (Google Test)
|
||||||
//
|
|
||||||
// The Google C++ Testing Framework (Google Test)
|
|
||||||
|
|
||||||
#include "gtest/gtest-test-part.h"
|
#include "gtest/gtest-test-part.h"
|
||||||
|
|
||||||
// Indicates that this translation unit is part of Google Test's
|
#include "gtest/internal/gtest-port.h"
|
||||||
// implementation. It must come before gtest-internal-inl.h is
|
|
||||||
// included, or there will be a compiler error. This trick exists to
|
|
||||||
// prevent the accidental inclusion of gtest-internal-inl.h in the
|
|
||||||
// user's code.
|
|
||||||
#define GTEST_IMPLEMENTATION_ 1
|
|
||||||
#include "src/gtest-internal-inl.h"
|
#include "src/gtest-internal-inl.h"
|
||||||
#undef GTEST_IMPLEMENTATION_
|
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
|
||||||
|
@ -50,18 +43,23 @@ using internal::GetUnitTestImpl;
|
||||||
// in it.
|
// in it.
|
||||||
std::string TestPartResult::ExtractSummary(const char* message) {
|
std::string TestPartResult::ExtractSummary(const char* message) {
|
||||||
const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
|
const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
|
||||||
return stack_trace == NULL ? message :
|
return stack_trace == nullptr ? message : std::string(message, stack_trace);
|
||||||
std::string(message, stack_trace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints a TestPartResult object.
|
// Prints a TestPartResult object.
|
||||||
std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
|
std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
|
||||||
return os
|
return os << internal::FormatFileLocation(result.file_name(),
|
||||||
<< result.file_name() << ":" << result.line_number() << ": "
|
result.line_number())
|
||||||
<< (result.type() == TestPartResult::kSuccess ? "Success" :
|
<< " "
|
||||||
result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
|
<< (result.type() == TestPartResult::kSuccess
|
||||||
"Non-fatal failure") << ":\n"
|
? "Success"
|
||||||
<< result.message() << std::endl;
|
: 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.
|
// Appends a TestPartResult to the array.
|
||||||
|
@ -76,7 +74,7 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
|
||||||
internal::posix::Abort();
|
internal::posix::Abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_[index];
|
return array_[static_cast<size_t>(index)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of TestPartResult objects in the array.
|
// Returns the number of TestPartResult objects in the array.
|
||||||
|
|
|
@ -26,17 +26,15 @@
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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-typed-test.h"
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
namespace testing {
|
namespace testing {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
#if GTEST_HAS_TYPED_TEST_P
|
|
||||||
|
|
||||||
// Skips to the first non-space char in str. Returns an empty string if str
|
// Skips to the first non-space char in str. Returns an empty string if str
|
||||||
// contains only whitespace characters.
|
// contains only whitespace characters.
|
||||||
static const char* SkipSpaces(const char* str) {
|
static const char* SkipSpaces(const char* str) {
|
||||||
|
@ -48,7 +46,7 @@ static const char* SkipSpaces(const char* str) {
|
||||||
static std::vector<std::string> SplitIntoTestNames(const char* src) {
|
static std::vector<std::string> SplitIntoTestNames(const char* src) {
|
||||||
std::vector<std::string> name_vec;
|
std::vector<std::string> name_vec;
|
||||||
src = SkipSpaces(src);
|
src = SkipSpaces(src);
|
||||||
for (; src != NULL; src = SkipComma(src)) {
|
for (; src != nullptr; src = SkipComma(src)) {
|
||||||
name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src)));
|
name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src)));
|
||||||
}
|
}
|
||||||
return name_vec;
|
return name_vec;
|
||||||
|
@ -57,8 +55,11 @@ static std::vector<std::string> SplitIntoTestNames(const char* src) {
|
||||||
// Verifies that registered_tests match the test names in
|
// Verifies that registered_tests match the test names in
|
||||||
// registered_tests_; returns registered_tests if successful, or
|
// registered_tests_; returns registered_tests if successful, or
|
||||||
// aborts the program otherwise.
|
// aborts the program otherwise.
|
||||||
const char* TypedTestCasePState::VerifyRegisteredTestNames(
|
const char* TypedTestSuitePState::VerifyRegisteredTestNames(
|
||||||
const char* file, int line, const char* registered_tests) {
|
const char* test_suite_name, const char* file, int line,
|
||||||
|
const char* registered_tests) {
|
||||||
|
RegisterTypeParameterizedTestSuite(test_suite_name, CodeLocation(file, line));
|
||||||
|
|
||||||
typedef RegisteredTestsMap::const_iterator RegisteredTestIter;
|
typedef RegisteredTestsMap::const_iterator RegisteredTestIter;
|
||||||
registered_ = true;
|
registered_ = true;
|
||||||
|
|
||||||
|
@ -75,21 +76,11 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool found = false;
|
if (registered_tests_.count(name) != 0) {
|
||||||
for (RegisteredTestIter it = registered_tests_.begin();
|
|
||||||
it != registered_tests_.end();
|
|
||||||
++it) {
|
|
||||||
if (name == it->first) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
tests.insert(name);
|
tests.insert(name);
|
||||||
} else {
|
} else {
|
||||||
errors << "No test named " << name
|
errors << "No test named " << name
|
||||||
<< " can be found in this test case.\n";
|
<< " can be found in this test suite.\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +103,5 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
|
||||||
return registered_tests;
|
return registered_tests;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // GTEST_HAS_TYPED_TEST_P
|
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -27,12 +27,28 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#if GTEST_OS_ESP8266 || GTEST_OS_ESP32
|
||||||
|
#if GTEST_OS_ESP8266
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void setup() {
|
||||||
|
testing::InitGoogleTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() { RUN_ALL_TESTS(); }
|
||||||
|
|
||||||
|
#if GTEST_OS_ESP8266
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
GTEST_API_ int main(int argc, char **argv) {
|
GTEST_API_ int main(int argc, char **argv) {
|
||||||
printf("Running main() from gtest_main.cc\n");
|
printf("Running main() from %s\n", __FILE__);
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
// Copyright 2010, 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.
|
|
||||||
//
|
|
||||||
// Author: vladl@google.com (Vlad Losev)
|
|
||||||
//
|
|
||||||
// Tests that verify interaction of exceptions and death tests.
|
|
||||||
|
|
||||||
#include "gtest/gtest-death-test.h"
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
|
|
||||||
#if GTEST_HAS_DEATH_TEST
|
|
||||||
|
|
||||||
# if GTEST_HAS_SEH
|
|
||||||
# include <windows.h> // For RaiseException().
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# include "gtest/gtest-spi.h"
|
|
||||||
|
|
||||||
# if GTEST_HAS_EXCEPTIONS
|
|
||||||
|
|
||||||
# include <exception> // For std::exception.
|
|
||||||
|
|
||||||
// Tests that death tests report thrown exceptions as failures and that the
|
|
||||||
// exceptions do not escape death test macros.
|
|
||||||
TEST(CxxExceptionDeathTest, ExceptionIsFailure) {
|
|
||||||
try {
|
|
||||||
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw 1, ""), "threw an exception");
|
|
||||||
} catch (...) { // NOLINT
|
|
||||||
FAIL() << "An exception escaped a death test macro invocation "
|
|
||||||
<< "with catch_exceptions "
|
|
||||||
<< (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestException : public std::exception {
|
|
||||||
public:
|
|
||||||
virtual const char* what() const throw() { return "exceptional message"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(CxxExceptionDeathTest, PrintsMessageForStdExceptions) {
|
|
||||||
// Verifies that the exception message is quoted in the failure text.
|
|
||||||
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""),
|
|
||||||
"exceptional message");
|
|
||||||
// Verifies that the location is mentioned in the failure text.
|
|
||||||
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""),
|
|
||||||
"gtest-death-test_ex_test.cc");
|
|
||||||
}
|
|
||||||
# endif // GTEST_HAS_EXCEPTIONS
|
|
||||||
|
|
||||||
# if GTEST_HAS_SEH
|
|
||||||
// Tests that enabling interception of SEH exceptions with the
|
|
||||||
// catch_exceptions flag does not interfere with SEH exceptions being
|
|
||||||
// treated as death by death tests.
|
|
||||||
TEST(SehExceptionDeasTest, CatchExceptionsDoesNotInterfere) {
|
|
||||||
EXPECT_DEATH(RaiseException(42, 0x0, 0, NULL), "")
|
|
||||||
<< "with catch_exceptions "
|
|
||||||
<< (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled");
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif // GTEST_HAS_DEATH_TEST
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
testing::InitGoogleTest(&argc, argv);
|
|
||||||
testing::GTEST_FLAG(catch_exceptions) = GTEST_ENABLE_CATCH_EXCEPTIONS_ != 0;
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,662 +0,0 @@
|
||||||
// Copyright 2008, 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.
|
|
||||||
//
|
|
||||||
// Authors: keith.ray@gmail.com (Keith Ray)
|
|
||||||
//
|
|
||||||
// Google Test filepath utilities
|
|
||||||
//
|
|
||||||
// This file tests classes and functions used internally by
|
|
||||||
// Google Test. They are subject to change without notice.
|
|
||||||
//
|
|
||||||
// This file is #included from gtest_unittest.cc, to avoid changing
|
|
||||||
// build or make-files for some existing Google Test clients. Do not
|
|
||||||
// #include this file anywhere else!
|
|
||||||
|
|
||||||
#include "gtest/internal/gtest-filepath.h"
|
|
||||||
#include "gtest/gtest.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_
|
|
||||||
|
|
||||||
#if GTEST_OS_WINDOWS_MOBILE
|
|
||||||
# include <windows.h> // NOLINT
|
|
||||||
#elif GTEST_OS_WINDOWS
|
|
||||||
# include <direct.h> // NOLINT
|
|
||||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
|
||||||
|
|
||||||
namespace testing {
|
|
||||||
namespace internal {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
#if GTEST_OS_WINDOWS_MOBILE
|
|
||||||
// TODO(wan@google.com): Move these to the POSIX adapter section in
|
|
||||||
// gtest-port.h.
|
|
||||||
|
|
||||||
// Windows CE doesn't have the remove C function.
|
|
||||||
int remove(const char* path) {
|
|
||||||
LPCWSTR wpath = String::AnsiToUtf16(path);
|
|
||||||
int ret = DeleteFile(wpath) ? 0 : -1;
|
|
||||||
delete [] wpath;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
// Windows CE doesn't have the _rmdir C function.
|
|
||||||
int _rmdir(const char* path) {
|
|
||||||
FilePath filepath(path);
|
|
||||||
LPCWSTR wpath = String::AnsiToUtf16(
|
|
||||||
filepath.RemoveTrailingPathSeparator().c_str());
|
|
||||||
int ret = RemoveDirectory(wpath) ? 0 : -1;
|
|
||||||
delete [] wpath;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
TEST(GetCurrentDirTest, ReturnsCurrentDir) {
|
|
||||||
const FilePath original_dir = FilePath::GetCurrentDir();
|
|
||||||
EXPECT_FALSE(original_dir.IsEmpty());
|
|
||||||
|
|
||||||
posix::ChDir(GTEST_PATH_SEP_);
|
|
||||||
const FilePath cwd = FilePath::GetCurrentDir();
|
|
||||||
posix::ChDir(original_dir.c_str());
|
|
||||||
|
|
||||||
# if GTEST_OS_WINDOWS
|
|
||||||
|
|
||||||
// Skips the ":".
|
|
||||||
const char* const cwd_without_drive = strchr(cwd.c_str(), ':');
|
|
||||||
ASSERT_TRUE(cwd_without_drive != NULL);
|
|
||||||
EXPECT_STREQ(GTEST_PATH_SEP_, cwd_without_drive + 1);
|
|
||||||
|
|
||||||
# else
|
|
||||||
|
|
||||||
EXPECT_EQ(GTEST_PATH_SEP_, cwd.string());
|
|
||||||
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
|
||||||
|
|
||||||
TEST(IsEmptyTest, ReturnsTrueForEmptyPath) {
|
|
||||||
EXPECT_TRUE(FilePath("").IsEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(IsEmptyTest, ReturnsFalseForNonEmptyPath) {
|
|
||||||
EXPECT_FALSE(FilePath("a").IsEmpty());
|
|
||||||
EXPECT_FALSE(FilePath(".").IsEmpty());
|
|
||||||
EXPECT_FALSE(FilePath("a/b").IsEmpty());
|
|
||||||
EXPECT_FALSE(FilePath("a\\b\\").IsEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryName "" -> ""
|
|
||||||
TEST(RemoveDirectoryNameTest, WhenEmptyName) {
|
|
||||||
EXPECT_EQ("", FilePath("").RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryName "afile" -> "afile"
|
|
||||||
TEST(RemoveDirectoryNameTest, ButNoDirectory) {
|
|
||||||
EXPECT_EQ("afile",
|
|
||||||
FilePath("afile").RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryName "/afile" -> "afile"
|
|
||||||
TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileName) {
|
|
||||||
EXPECT_EQ("afile",
|
|
||||||
FilePath(GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryName "adir/" -> ""
|
|
||||||
TEST(RemoveDirectoryNameTest, WhereThereIsNoFileName) {
|
|
||||||
EXPECT_EQ("",
|
|
||||||
FilePath("adir" GTEST_PATH_SEP_).RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryName "adir/afile" -> "afile"
|
|
||||||
TEST(RemoveDirectoryNameTest, ShouldGiveFileName) {
|
|
||||||
EXPECT_EQ("afile",
|
|
||||||
FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryName "adir/subdir/afile" -> "afile"
|
|
||||||
TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName) {
|
|
||||||
EXPECT_EQ("afile",
|
|
||||||
FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile")
|
|
||||||
.RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#if GTEST_HAS_ALT_PATH_SEP_
|
|
||||||
|
|
||||||
// Tests that RemoveDirectoryName() works with the alternate separator
|
|
||||||
// on Windows.
|
|
||||||
|
|
||||||
// RemoveDirectoryName("/afile") -> "afile"
|
|
||||||
TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileNameForAlternateSeparator) {
|
|
||||||
EXPECT_EQ("afile", FilePath("/afile").RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryName("adir/") -> ""
|
|
||||||
TEST(RemoveDirectoryNameTest, WhereThereIsNoFileNameForAlternateSeparator) {
|
|
||||||
EXPECT_EQ("", FilePath("adir/").RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryName("adir/afile") -> "afile"
|
|
||||||
TEST(RemoveDirectoryNameTest, ShouldGiveFileNameForAlternateSeparator) {
|
|
||||||
EXPECT_EQ("afile", FilePath("adir/afile").RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryName("adir/subdir/afile") -> "afile"
|
|
||||||
TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileNameForAlternateSeparator) {
|
|
||||||
EXPECT_EQ("afile",
|
|
||||||
FilePath("adir/subdir/afile").RemoveDirectoryName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// RemoveFileName "" -> "./"
|
|
||||||
TEST(RemoveFileNameTest, EmptyName) {
|
|
||||||
#if GTEST_OS_WINDOWS_MOBILE
|
|
||||||
// On Windows CE, we use the root as the current directory.
|
|
||||||
EXPECT_EQ(GTEST_PATH_SEP_, FilePath("").RemoveFileName().string());
|
|
||||||
#else
|
|
||||||
EXPECT_EQ("." GTEST_PATH_SEP_, FilePath("").RemoveFileName().string());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFileName "adir/" -> "adir/"
|
|
||||||
TEST(RemoveFileNameTest, ButNoFile) {
|
|
||||||
EXPECT_EQ("adir" GTEST_PATH_SEP_,
|
|
||||||
FilePath("adir" GTEST_PATH_SEP_).RemoveFileName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFileName "adir/afile" -> "adir/"
|
|
||||||
TEST(RemoveFileNameTest, GivesDirName) {
|
|
||||||
EXPECT_EQ("adir" GTEST_PATH_SEP_,
|
|
||||||
FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveFileName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFileName "adir/subdir/afile" -> "adir/subdir/"
|
|
||||||
TEST(RemoveFileNameTest, GivesDirAndSubDirName) {
|
|
||||||
EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_,
|
|
||||||
FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile")
|
|
||||||
.RemoveFileName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFileName "/afile" -> "/"
|
|
||||||
TEST(RemoveFileNameTest, GivesRootDir) {
|
|
||||||
EXPECT_EQ(GTEST_PATH_SEP_,
|
|
||||||
FilePath(GTEST_PATH_SEP_ "afile").RemoveFileName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#if GTEST_HAS_ALT_PATH_SEP_
|
|
||||||
|
|
||||||
// Tests that RemoveFileName() works with the alternate separator on
|
|
||||||
// Windows.
|
|
||||||
|
|
||||||
// RemoveFileName("adir/") -> "adir/"
|
|
||||||
TEST(RemoveFileNameTest, ButNoFileForAlternateSeparator) {
|
|
||||||
EXPECT_EQ("adir" GTEST_PATH_SEP_,
|
|
||||||
FilePath("adir/").RemoveFileName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFileName("adir/afile") -> "adir/"
|
|
||||||
TEST(RemoveFileNameTest, GivesDirNameForAlternateSeparator) {
|
|
||||||
EXPECT_EQ("adir" GTEST_PATH_SEP_,
|
|
||||||
FilePath("adir/afile").RemoveFileName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFileName("adir/subdir/afile") -> "adir/subdir/"
|
|
||||||
TEST(RemoveFileNameTest, GivesDirAndSubDirNameForAlternateSeparator) {
|
|
||||||
EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_,
|
|
||||||
FilePath("adir/subdir/afile").RemoveFileName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFileName("/afile") -> "\"
|
|
||||||
TEST(RemoveFileNameTest, GivesRootDirForAlternateSeparator) {
|
|
||||||
EXPECT_EQ(GTEST_PATH_SEP_, FilePath("/afile").RemoveFileName().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST(MakeFileNameTest, GenerateWhenNumberIsZero) {
|
|
||||||
FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"),
|
|
||||||
0, "xml");
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(MakeFileNameTest, GenerateFileNameNumberGtZero) {
|
|
||||||
FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"),
|
|
||||||
12, "xml");
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberIsZero) {
|
|
||||||
FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_),
|
|
||||||
FilePath("bar"), 0, "xml");
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberGtZero) {
|
|
||||||
FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_),
|
|
||||||
FilePath("bar"), 12, "xml");
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(MakeFileNameTest, GenerateWhenNumberIsZeroAndDirIsEmpty) {
|
|
||||||
FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"),
|
|
||||||
0, "xml");
|
|
||||||
EXPECT_EQ("bar.xml", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(MakeFileNameTest, GenerateWhenNumberIsNotZeroAndDirIsEmpty) {
|
|
||||||
FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"),
|
|
||||||
14, "xml");
|
|
||||||
EXPECT_EQ("bar_14.xml", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ConcatPathsTest, WorksWhenDirDoesNotEndWithPathSep) {
|
|
||||||
FilePath actual = FilePath::ConcatPaths(FilePath("foo"),
|
|
||||||
FilePath("bar.xml"));
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ConcatPathsTest, WorksWhenPath1EndsWithPathSep) {
|
|
||||||
FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_),
|
|
||||||
FilePath("bar.xml"));
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ConcatPathsTest, Path1BeingEmpty) {
|
|
||||||
FilePath actual = FilePath::ConcatPaths(FilePath(""),
|
|
||||||
FilePath("bar.xml"));
|
|
||||||
EXPECT_EQ("bar.xml", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ConcatPathsTest, Path2BeingEmpty) {
|
|
||||||
FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath(""));
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_, actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ConcatPathsTest, BothPathBeingEmpty) {
|
|
||||||
FilePath actual = FilePath::ConcatPaths(FilePath(""),
|
|
||||||
FilePath(""));
|
|
||||||
EXPECT_EQ("", actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ConcatPathsTest, Path1ContainsPathSep) {
|
|
||||||
FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_ "bar"),
|
|
||||||
FilePath("foobar.xml"));
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "foobar.xml",
|
|
||||||
actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ConcatPathsTest, Path2ContainsPathSep) {
|
|
||||||
FilePath actual = FilePath::ConcatPaths(
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_),
|
|
||||||
FilePath("bar" GTEST_PATH_SEP_ "bar.xml"));
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "bar.xml",
|
|
||||||
actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ConcatPathsTest, Path2EndsWithPathSep) {
|
|
||||||
FilePath actual = FilePath::ConcatPaths(FilePath("foo"),
|
|
||||||
FilePath("bar" GTEST_PATH_SEP_));
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_, actual.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveTrailingPathSeparator "" -> ""
|
|
||||||
TEST(RemoveTrailingPathSeparatorTest, EmptyString) {
|
|
||||||
EXPECT_EQ("", FilePath("").RemoveTrailingPathSeparator().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveTrailingPathSeparator "foo" -> "foo"
|
|
||||||
TEST(RemoveTrailingPathSeparatorTest, FileNoSlashString) {
|
|
||||||
EXPECT_EQ("foo", FilePath("foo").RemoveTrailingPathSeparator().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveTrailingPathSeparator "foo/" -> "foo"
|
|
||||||
TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveTrailingSeparator) {
|
|
||||||
EXPECT_EQ("foo",
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_).RemoveTrailingPathSeparator().string());
|
|
||||||
#if GTEST_HAS_ALT_PATH_SEP_
|
|
||||||
EXPECT_EQ("foo", FilePath("foo/").RemoveTrailingPathSeparator().string());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveTrailingPathSeparator "foo/bar/" -> "foo/bar/"
|
|
||||||
TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveLastSeparator) {
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_)
|
|
||||||
.RemoveTrailingPathSeparator().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveTrailingPathSeparator "foo/bar" -> "foo/bar"
|
|
||||||
TEST(RemoveTrailingPathSeparatorTest, ShouldReturnUnmodified) {
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_ "bar")
|
|
||||||
.RemoveTrailingPathSeparator().string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DirectoryTest, RootDirectoryExists) {
|
|
||||||
#if GTEST_OS_WINDOWS // We are on Windows.
|
|
||||||
char current_drive[_MAX_PATH]; // NOLINT
|
|
||||||
current_drive[0] = static_cast<char>(_getdrive() + 'A' - 1);
|
|
||||||
current_drive[1] = ':';
|
|
||||||
current_drive[2] = '\\';
|
|
||||||
current_drive[3] = '\0';
|
|
||||||
EXPECT_TRUE(FilePath(current_drive).DirectoryExists());
|
|
||||||
#else
|
|
||||||
EXPECT_TRUE(FilePath("/").DirectoryExists());
|
|
||||||
#endif // GTEST_OS_WINDOWS
|
|
||||||
}
|
|
||||||
|
|
||||||
#if GTEST_OS_WINDOWS
|
|
||||||
TEST(DirectoryTest, RootOfWrongDriveDoesNotExists) {
|
|
||||||
const int saved_drive_ = _getdrive();
|
|
||||||
// Find a drive that doesn't exist. Start with 'Z' to avoid common ones.
|
|
||||||
for (char drive = 'Z'; drive >= 'A'; drive--)
|
|
||||||
if (_chdrive(drive - 'A' + 1) == -1) {
|
|
||||||
char non_drive[_MAX_PATH]; // NOLINT
|
|
||||||
non_drive[0] = drive;
|
|
||||||
non_drive[1] = ':';
|
|
||||||
non_drive[2] = '\\';
|
|
||||||
non_drive[3] = '\0';
|
|
||||||
EXPECT_FALSE(FilePath(non_drive).DirectoryExists());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_chdrive(saved_drive_);
|
|
||||||
}
|
|
||||||
#endif // GTEST_OS_WINDOWS
|
|
||||||
|
|
||||||
#if !GTEST_OS_WINDOWS_MOBILE
|
|
||||||
// Windows CE _does_ consider an empty directory to exist.
|
|
||||||
TEST(DirectoryTest, EmptyPathDirectoryDoesNotExist) {
|
|
||||||
EXPECT_FALSE(FilePath("").DirectoryExists());
|
|
||||||
}
|
|
||||||
#endif // !GTEST_OS_WINDOWS_MOBILE
|
|
||||||
|
|
||||||
TEST(DirectoryTest, CurrentDirectoryExists) {
|
|
||||||
#if GTEST_OS_WINDOWS // We are on Windows.
|
|
||||||
# ifndef _WIN32_CE // Windows CE doesn't have a current directory.
|
|
||||||
|
|
||||||
EXPECT_TRUE(FilePath(".").DirectoryExists());
|
|
||||||
EXPECT_TRUE(FilePath(".\\").DirectoryExists());
|
|
||||||
|
|
||||||
# endif // _WIN32_CE
|
|
||||||
#else
|
|
||||||
EXPECT_TRUE(FilePath(".").DirectoryExists());
|
|
||||||
EXPECT_TRUE(FilePath("./").DirectoryExists());
|
|
||||||
#endif // GTEST_OS_WINDOWS
|
|
||||||
}
|
|
||||||
|
|
||||||
// "foo/bar" == foo//bar" == "foo///bar"
|
|
||||||
TEST(NormalizeTest, MultipleConsecutiveSepaparatorsInMidstring) {
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_ "bar").string());
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string());
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_
|
|
||||||
GTEST_PATH_SEP_ "bar").string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// "/bar" == //bar" == "///bar"
|
|
||||||
TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringStart) {
|
|
||||||
EXPECT_EQ(GTEST_PATH_SEP_ "bar",
|
|
||||||
FilePath(GTEST_PATH_SEP_ "bar").string());
|
|
||||||
EXPECT_EQ(GTEST_PATH_SEP_ "bar",
|
|
||||||
FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string());
|
|
||||||
EXPECT_EQ(GTEST_PATH_SEP_ "bar",
|
|
||||||
FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// "foo/" == foo//" == "foo///"
|
|
||||||
TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringEnd) {
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_,
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_).string());
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_,
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_).string());
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_,
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_).string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#if GTEST_HAS_ALT_PATH_SEP_
|
|
||||||
|
|
||||||
// Tests that separators at the end of the string are normalized
|
|
||||||
// regardless of their combination (e.g. "foo\" =="foo/\" ==
|
|
||||||
// "foo\\/").
|
|
||||||
TEST(NormalizeTest, MixAlternateSeparatorAtStringEnd) {
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_,
|
|
||||||
FilePath("foo/").string());
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_,
|
|
||||||
FilePath("foo" GTEST_PATH_SEP_ "/").string());
|
|
||||||
EXPECT_EQ("foo" GTEST_PATH_SEP_,
|
|
||||||
FilePath("foo//" GTEST_PATH_SEP_).string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST(AssignmentOperatorTest, DefaultAssignedToNonDefault) {
|
|
||||||
FilePath default_path;
|
|
||||||
FilePath non_default_path("path");
|
|
||||||
non_default_path = default_path;
|
|
||||||
EXPECT_EQ("", non_default_path.string());
|
|
||||||
EXPECT_EQ("", default_path.string()); // RHS var is unchanged.
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AssignmentOperatorTest, NonDefaultAssignedToDefault) {
|
|
||||||
FilePath non_default_path("path");
|
|
||||||
FilePath default_path;
|
|
||||||
default_path = non_default_path;
|
|
||||||
EXPECT_EQ("path", default_path.string());
|
|
||||||
EXPECT_EQ("path", non_default_path.string()); // RHS var is unchanged.
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AssignmentOperatorTest, ConstAssignedToNonConst) {
|
|
||||||
const FilePath const_default_path("const_path");
|
|
||||||
FilePath non_default_path("path");
|
|
||||||
non_default_path = const_default_path;
|
|
||||||
EXPECT_EQ("const_path", non_default_path.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
class DirectoryCreationTest : public Test {
|
|
||||||
protected:
|
|
||||||
virtual void SetUp() {
|
|
||||||
testdata_path_.Set(FilePath(
|
|
||||||
TempDir() + GetCurrentExecutableName().string() +
|
|
||||||
"_directory_creation" GTEST_PATH_SEP_ "test" GTEST_PATH_SEP_));
|
|
||||||
testdata_file_.Set(testdata_path_.RemoveTrailingPathSeparator());
|
|
||||||
|
|
||||||
unique_file0_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"),
|
|
||||||
0, "txt"));
|
|
||||||
unique_file1_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"),
|
|
||||||
1, "txt"));
|
|
||||||
|
|
||||||
remove(testdata_file_.c_str());
|
|
||||||
remove(unique_file0_.c_str());
|
|
||||||
remove(unique_file1_.c_str());
|
|
||||||
posix::RmDir(testdata_path_.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void TearDown() {
|
|
||||||
remove(testdata_file_.c_str());
|
|
||||||
remove(unique_file0_.c_str());
|
|
||||||
remove(unique_file1_.c_str());
|
|
||||||
posix::RmDir(testdata_path_.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateTextFile(const char* filename) {
|
|
||||||
FILE* f = posix::FOpen(filename, "w");
|
|
||||||
fprintf(f, "text\n");
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strings representing a directory and a file, with identical paths
|
|
||||||
// except for the trailing separator character that distinquishes
|
|
||||||
// a directory named 'test' from a file named 'test'. Example names:
|
|
||||||
FilePath testdata_path_; // "/tmp/directory_creation/test/"
|
|
||||||
FilePath testdata_file_; // "/tmp/directory_creation/test"
|
|
||||||
FilePath unique_file0_; // "/tmp/directory_creation/test/unique.txt"
|
|
||||||
FilePath unique_file1_; // "/tmp/directory_creation/test/unique_1.txt"
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(DirectoryCreationTest, CreateDirectoriesRecursively) {
|
|
||||||
EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.string();
|
|
||||||
EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively());
|
|
||||||
EXPECT_TRUE(testdata_path_.DirectoryExists());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DirectoryCreationTest, CreateDirectoriesForAlreadyExistingPath) {
|
|
||||||
EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.string();
|
|
||||||
EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively());
|
|
||||||
// Call 'create' again... should still succeed.
|
|
||||||
EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DirectoryCreationTest, CreateDirectoriesAndUniqueFilename) {
|
|
||||||
FilePath file_path(FilePath::GenerateUniqueFileName(testdata_path_,
|
|
||||||
FilePath("unique"), "txt"));
|
|
||||||
EXPECT_EQ(unique_file0_.string(), file_path.string());
|
|
||||||
EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file not there
|
|
||||||
|
|
||||||
testdata_path_.CreateDirectoriesRecursively();
|
|
||||||
EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file still not there
|
|
||||||
CreateTextFile(file_path.c_str());
|
|
||||||
EXPECT_TRUE(file_path.FileOrDirectoryExists());
|
|
||||||
|
|
||||||
FilePath file_path2(FilePath::GenerateUniqueFileName(testdata_path_,
|
|
||||||
FilePath("unique"), "txt"));
|
|
||||||
EXPECT_EQ(unique_file1_.string(), file_path2.string());
|
|
||||||
EXPECT_FALSE(file_path2.FileOrDirectoryExists()); // file not there
|
|
||||||
CreateTextFile(file_path2.c_str());
|
|
||||||
EXPECT_TRUE(file_path2.FileOrDirectoryExists());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DirectoryCreationTest, CreateDirectoriesFail) {
|
|
||||||
// force a failure by putting a file where we will try to create a directory.
|
|
||||||
CreateTextFile(testdata_file_.c_str());
|
|
||||||
EXPECT_TRUE(testdata_file_.FileOrDirectoryExists());
|
|
||||||
EXPECT_FALSE(testdata_file_.DirectoryExists());
|
|
||||||
EXPECT_FALSE(testdata_file_.CreateDirectoriesRecursively());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(NoDirectoryCreationTest, CreateNoDirectoriesForDefaultXmlFile) {
|
|
||||||
const FilePath test_detail_xml("test_detail.xml");
|
|
||||||
EXPECT_FALSE(test_detail_xml.CreateDirectoriesRecursively());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, DefaultConstructor) {
|
|
||||||
FilePath fp;
|
|
||||||
EXPECT_EQ("", fp.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, CharAndCopyConstructors) {
|
|
||||||
const FilePath fp("spicy");
|
|
||||||
EXPECT_EQ("spicy", fp.string());
|
|
||||||
|
|
||||||
const FilePath fp_copy(fp);
|
|
||||||
EXPECT_EQ("spicy", fp_copy.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, StringConstructor) {
|
|
||||||
const FilePath fp(std::string("cider"));
|
|
||||||
EXPECT_EQ("cider", fp.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, Set) {
|
|
||||||
const FilePath apple("apple");
|
|
||||||
FilePath mac("mac");
|
|
||||||
mac.Set(apple); // Implement Set() since overloading operator= is forbidden.
|
|
||||||
EXPECT_EQ("apple", mac.string());
|
|
||||||
EXPECT_EQ("apple", apple.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, ToString) {
|
|
||||||
const FilePath file("drink");
|
|
||||||
EXPECT_EQ("drink", file.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, RemoveExtension) {
|
|
||||||
EXPECT_EQ("app", FilePath("app.cc").RemoveExtension("cc").string());
|
|
||||||
EXPECT_EQ("app", FilePath("app.exe").RemoveExtension("exe").string());
|
|
||||||
EXPECT_EQ("APP", FilePath("APP.EXE").RemoveExtension("exe").string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, RemoveExtensionWhenThereIsNoExtension) {
|
|
||||||
EXPECT_EQ("app", FilePath("app").RemoveExtension("exe").string());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, IsDirectory) {
|
|
||||||
EXPECT_FALSE(FilePath("cola").IsDirectory());
|
|
||||||
EXPECT_TRUE(FilePath("koala" GTEST_PATH_SEP_).IsDirectory());
|
|
||||||
#if GTEST_HAS_ALT_PATH_SEP_
|
|
||||||
EXPECT_TRUE(FilePath("koala/").IsDirectory());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, IsAbsolutePath) {
|
|
||||||
EXPECT_FALSE(FilePath("is" GTEST_PATH_SEP_ "relative").IsAbsolutePath());
|
|
||||||
EXPECT_FALSE(FilePath("").IsAbsolutePath());
|
|
||||||
#if GTEST_OS_WINDOWS
|
|
||||||
EXPECT_TRUE(FilePath("c:\\" GTEST_PATH_SEP_ "is_not"
|
|
||||||
GTEST_PATH_SEP_ "relative").IsAbsolutePath());
|
|
||||||
EXPECT_FALSE(FilePath("c:foo" GTEST_PATH_SEP_ "bar").IsAbsolutePath());
|
|
||||||
EXPECT_TRUE(FilePath("c:/" GTEST_PATH_SEP_ "is_not"
|
|
||||||
GTEST_PATH_SEP_ "relative").IsAbsolutePath());
|
|
||||||
#else
|
|
||||||
EXPECT_TRUE(FilePath(GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative")
|
|
||||||
.IsAbsolutePath());
|
|
||||||
#endif // GTEST_OS_WINDOWS
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FilePathTest, IsRootDirectory) {
|
|
||||||
#if GTEST_OS_WINDOWS
|
|
||||||
EXPECT_TRUE(FilePath("a:\\").IsRootDirectory());
|
|
||||||
EXPECT_TRUE(FilePath("Z:/").IsRootDirectory());
|
|
||||||
EXPECT_TRUE(FilePath("e://").IsRootDirectory());
|
|
||||||
EXPECT_FALSE(FilePath("").IsRootDirectory());
|
|
||||||
EXPECT_FALSE(FilePath("b:").IsRootDirectory());
|
|
||||||
EXPECT_FALSE(FilePath("b:a").IsRootDirectory());
|
|
||||||
EXPECT_FALSE(FilePath("8:/").IsRootDirectory());
|
|
||||||
EXPECT_FALSE(FilePath("c|/").IsRootDirectory());
|
|
||||||
#else
|
|
||||||
EXPECT_TRUE(FilePath("/").IsRootDirectory());
|
|
||||||
EXPECT_TRUE(FilePath("//").IsRootDirectory());
|
|
||||||
EXPECT_FALSE(FilePath("").IsRootDirectory());
|
|
||||||
EXPECT_FALSE(FilePath("\\").IsRootDirectory());
|
|
||||||
EXPECT_FALSE(FilePath("/x").IsRootDirectory());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace testing
|
|
|
@ -1,154 +0,0 @@
|
||||||
// Copyright 2003, 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.
|
|
||||||
//
|
|
||||||
// Authors: Dan Egnor (egnor@google.com)
|
|
||||||
// Ported to Windows: Vadim Berman (vadimb@google.com)
|
|
||||||
|
|
||||||
#include "gtest/internal/gtest-linked_ptr.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using testing::Message;
|
|
||||||
using testing::internal::linked_ptr;
|
|
||||||
|
|
||||||
int num;
|
|
||||||
Message* history = NULL;
|
|
||||||
|
|
||||||
// Class which tracks allocation/deallocation
|
|
||||||
class A {
|
|
||||||
public:
|
|
||||||
A(): mynum(num++) { *history << "A" << mynum << " ctor\n"; }
|
|
||||||
virtual ~A() { *history << "A" << mynum << " dtor\n"; }
|
|
||||||
virtual void Use() { *history << "A" << mynum << " use\n"; }
|
|
||||||
protected:
|
|
||||||
int mynum;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Subclass
|
|
||||||
class B : public A {
|
|
||||||
public:
|
|
||||||
B() { *history << "B" << mynum << " ctor\n"; }
|
|
||||||
~B() { *history << "B" << mynum << " dtor\n"; }
|
|
||||||
virtual void Use() { *history << "B" << mynum << " use\n"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class LinkedPtrTest : public testing::Test {
|
|
||||||
public:
|
|
||||||
LinkedPtrTest() {
|
|
||||||
num = 0;
|
|
||||||
history = new Message;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~LinkedPtrTest() {
|
|
||||||
delete history;
|
|
||||||
history = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(LinkedPtrTest, GeneralTest) {
|
|
||||||
{
|
|
||||||
linked_ptr<A> a0, a1, a2;
|
|
||||||
// Use explicit function call notation here to suppress self-assign warning.
|
|
||||||
a0.operator=(a0);
|
|
||||||
a1 = a2;
|
|
||||||
ASSERT_EQ(a0.get(), static_cast<A*>(NULL));
|
|
||||||
ASSERT_EQ(a1.get(), static_cast<A*>(NULL));
|
|
||||||
ASSERT_EQ(a2.get(), static_cast<A*>(NULL));
|
|
||||||
ASSERT_TRUE(a0 == NULL);
|
|
||||||
ASSERT_TRUE(a1 == NULL);
|
|
||||||
ASSERT_TRUE(a2 == NULL);
|
|
||||||
|
|
||||||
{
|
|
||||||
linked_ptr<A> a3(new A);
|
|
||||||
a0 = a3;
|
|
||||||
ASSERT_TRUE(a0 == a3);
|
|
||||||
ASSERT_TRUE(a0 != NULL);
|
|
||||||
ASSERT_TRUE(a0.get() == a3);
|
|
||||||
ASSERT_TRUE(a0 == a3.get());
|
|
||||||
linked_ptr<A> a4(a0);
|
|
||||||
a1 = a4;
|
|
||||||
linked_ptr<A> a5(new A);
|
|
||||||
ASSERT_TRUE(a5.get() != a3);
|
|
||||||
ASSERT_TRUE(a5 != a3.get());
|
|
||||||
a2 = a5;
|
|
||||||
linked_ptr<B> b0(new B);
|
|
||||||
linked_ptr<A> a6(b0);
|
|
||||||
ASSERT_TRUE(b0 == a6);
|
|
||||||
ASSERT_TRUE(a6 == b0);
|
|
||||||
ASSERT_TRUE(b0 != NULL);
|
|
||||||
a5 = b0;
|
|
||||||
a5 = b0;
|
|
||||||
a3->Use();
|
|
||||||
a4->Use();
|
|
||||||
a5->Use();
|
|
||||||
a6->Use();
|
|
||||||
b0->Use();
|
|
||||||
(*b0).Use();
|
|
||||||
b0.get()->Use();
|
|
||||||
}
|
|
||||||
|
|
||||||
a0->Use();
|
|
||||||
a1->Use();
|
|
||||||
a2->Use();
|
|
||||||
|
|
||||||
a1 = a2;
|
|
||||||
a2.reset(new A);
|
|
||||||
a0.reset();
|
|
||||||
|
|
||||||
linked_ptr<A> a7;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_STREQ(
|
|
||||||
"A0 ctor\n"
|
|
||||||
"A1 ctor\n"
|
|
||||||
"A2 ctor\n"
|
|
||||||
"B2 ctor\n"
|
|
||||||
"A0 use\n"
|
|
||||||
"A0 use\n"
|
|
||||||
"B2 use\n"
|
|
||||||
"B2 use\n"
|
|
||||||
"B2 use\n"
|
|
||||||
"B2 use\n"
|
|
||||||
"B2 use\n"
|
|
||||||
"B2 dtor\n"
|
|
||||||
"A2 dtor\n"
|
|
||||||
"A0 use\n"
|
|
||||||
"A0 use\n"
|
|
||||||
"A1 use\n"
|
|
||||||
"A3 ctor\n"
|
|
||||||
"A0 dtor\n"
|
|
||||||
"A3 dtor\n"
|
|
||||||
"A1 dtor\n",
|
|
||||||
history->GetString().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // Unnamed namespace
|
|
|
@ -1,311 +0,0 @@
|
||||||
// Copyright 2009 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.
|
|
||||||
//
|
|
||||||
// Author: vladl@google.com (Vlad Losev)
|
|
||||||
//
|
|
||||||
// The Google C++ Testing Framework (Google Test)
|
|
||||||
//
|
|
||||||
// This file verifies Google Test event listeners receive events at the
|
|
||||||
// right times.
|
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using ::testing::AddGlobalTestEnvironment;
|
|
||||||
using ::testing::Environment;
|
|
||||||
using ::testing::InitGoogleTest;
|
|
||||||
using ::testing::Test;
|
|
||||||
using ::testing::TestCase;
|
|
||||||
using ::testing::TestEventListener;
|
|
||||||
using ::testing::TestInfo;
|
|
||||||
using ::testing::TestPartResult;
|
|
||||||
using ::testing::UnitTest;
|
|
||||||
|
|
||||||
// Used by tests to register their events.
|
|
||||||
std::vector<std::string>* g_events = NULL;
|
|
||||||
|
|
||||||
namespace testing {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
class EventRecordingListener : public TestEventListener {
|
|
||||||
public:
|
|
||||||
explicit EventRecordingListener(const char* name) : name_(name) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnTestProgramStart"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
|
|
||||||
int iteration) {
|
|
||||||
Message message;
|
|
||||||
message << GetFullMethodName("OnTestIterationStart")
|
|
||||||
<< "(" << iteration << ")";
|
|
||||||
g_events->push_back(message.GetString());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpStart"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpEnd"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnTestCaseStart(const TestCase& /*test_case*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnTestCaseStart"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnTestStart(const TestInfo& /*test_info*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnTestStart"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnTestPartResult"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnTestEnd(const TestInfo& /*test_info*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnTestEnd"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnTestCaseEnd"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownStart"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownEnd"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
|
|
||||||
int iteration) {
|
|
||||||
Message message;
|
|
||||||
message << GetFullMethodName("OnTestIterationEnd")
|
|
||||||
<< "(" << iteration << ")";
|
|
||||||
g_events->push_back(message.GetString());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {
|
|
||||||
g_events->push_back(GetFullMethodName("OnTestProgramEnd"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string GetFullMethodName(const char* name) {
|
|
||||||
return name_ + "." + name;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EnvironmentInvocationCatcher : public Environment {
|
|
||||||
protected:
|
|
||||||
virtual void SetUp() {
|
|
||||||
g_events->push_back("Environment::SetUp");
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void TearDown() {
|
|
||||||
g_events->push_back("Environment::TearDown");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ListenerTest : public Test {
|
|
||||||
protected:
|
|
||||||
static void SetUpTestCase() {
|
|
||||||
g_events->push_back("ListenerTest::SetUpTestCase");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TearDownTestCase() {
|
|
||||||
g_events->push_back("ListenerTest::TearDownTestCase");
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void SetUp() {
|
|
||||||
g_events->push_back("ListenerTest::SetUp");
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void TearDown() {
|
|
||||||
g_events->push_back("ListenerTest::TearDown");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(ListenerTest, DoesFoo) {
|
|
||||||
// Test execution order within a test case is not guaranteed so we are not
|
|
||||||
// recording the test name.
|
|
||||||
g_events->push_back("ListenerTest::* Test Body");
|
|
||||||
SUCCEED(); // Triggers OnTestPartResult.
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ListenerTest, DoesBar) {
|
|
||||||
g_events->push_back("ListenerTest::* Test Body");
|
|
||||||
SUCCEED(); // Triggers OnTestPartResult.
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
} // namespace testing
|
|
||||||
|
|
||||||
using ::testing::internal::EnvironmentInvocationCatcher;
|
|
||||||
using ::testing::internal::EventRecordingListener;
|
|
||||||
|
|
||||||
void VerifyResults(const std::vector<std::string>& data,
|
|
||||||
const char* const* expected_data,
|
|
||||||
size_t expected_data_size) {
|
|
||||||
const size_t actual_size = data.size();
|
|
||||||
// If the following assertion fails, a new entry will be appended to
|
|
||||||
// data. Hence we save data.size() first.
|
|
||||||
EXPECT_EQ(expected_data_size, actual_size);
|
|
||||||
|
|
||||||
// Compares the common prefix.
|
|
||||||
const size_t shorter_size = expected_data_size <= actual_size ?
|
|
||||||
expected_data_size : actual_size;
|
|
||||||
size_t i = 0;
|
|
||||||
for (; i < shorter_size; ++i) {
|
|
||||||
ASSERT_STREQ(expected_data[i], data[i].c_str())
|
|
||||||
<< "at position " << i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prints extra elements in the actual data.
|
|
||||||
for (; i < actual_size; ++i) {
|
|
||||||
printf(" Actual event #%lu: %s\n",
|
|
||||||
static_cast<unsigned long>(i), data[i].c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
std::vector<std::string> events;
|
|
||||||
g_events = &events;
|
|
||||||
InitGoogleTest(&argc, argv);
|
|
||||||
|
|
||||||
UnitTest::GetInstance()->listeners().Append(
|
|
||||||
new EventRecordingListener("1st"));
|
|
||||||
UnitTest::GetInstance()->listeners().Append(
|
|
||||||
new EventRecordingListener("2nd"));
|
|
||||||
|
|
||||||
AddGlobalTestEnvironment(new EnvironmentInvocationCatcher);
|
|
||||||
|
|
||||||
GTEST_CHECK_(events.size() == 0)
|
|
||||||
<< "AddGlobalTestEnvironment should not generate any events itself.";
|
|
||||||
|
|
||||||
::testing::GTEST_FLAG(repeat) = 2;
|
|
||||||
int ret_val = RUN_ALL_TESTS();
|
|
||||||
|
|
||||||
const char* const expected_events[] = {
|
|
||||||
"1st.OnTestProgramStart",
|
|
||||||
"2nd.OnTestProgramStart",
|
|
||||||
"1st.OnTestIterationStart(0)",
|
|
||||||
"2nd.OnTestIterationStart(0)",
|
|
||||||
"1st.OnEnvironmentsSetUpStart",
|
|
||||||
"2nd.OnEnvironmentsSetUpStart",
|
|
||||||
"Environment::SetUp",
|
|
||||||
"2nd.OnEnvironmentsSetUpEnd",
|
|
||||||
"1st.OnEnvironmentsSetUpEnd",
|
|
||||||
"1st.OnTestCaseStart",
|
|
||||||
"2nd.OnTestCaseStart",
|
|
||||||
"ListenerTest::SetUpTestCase",
|
|
||||||
"1st.OnTestStart",
|
|
||||||
"2nd.OnTestStart",
|
|
||||||
"ListenerTest::SetUp",
|
|
||||||
"ListenerTest::* Test Body",
|
|
||||||
"1st.OnTestPartResult",
|
|
||||||
"2nd.OnTestPartResult",
|
|
||||||
"ListenerTest::TearDown",
|
|
||||||
"2nd.OnTestEnd",
|
|
||||||
"1st.OnTestEnd",
|
|
||||||
"1st.OnTestStart",
|
|
||||||
"2nd.OnTestStart",
|
|
||||||
"ListenerTest::SetUp",
|
|
||||||
"ListenerTest::* Test Body",
|
|
||||||
"1st.OnTestPartResult",
|
|
||||||
"2nd.OnTestPartResult",
|
|
||||||
"ListenerTest::TearDown",
|
|
||||||
"2nd.OnTestEnd",
|
|
||||||
"1st.OnTestEnd",
|
|
||||||
"ListenerTest::TearDownTestCase",
|
|
||||||
"2nd.OnTestCaseEnd",
|
|
||||||
"1st.OnTestCaseEnd",
|
|
||||||
"1st.OnEnvironmentsTearDownStart",
|
|
||||||
"2nd.OnEnvironmentsTearDownStart",
|
|
||||||
"Environment::TearDown",
|
|
||||||
"2nd.OnEnvironmentsTearDownEnd",
|
|
||||||
"1st.OnEnvironmentsTearDownEnd",
|
|
||||||
"2nd.OnTestIterationEnd(0)",
|
|
||||||
"1st.OnTestIterationEnd(0)",
|
|
||||||
"1st.OnTestIterationStart(1)",
|
|
||||||
"2nd.OnTestIterationStart(1)",
|
|
||||||
"1st.OnEnvironmentsSetUpStart",
|
|
||||||
"2nd.OnEnvironmentsSetUpStart",
|
|
||||||
"Environment::SetUp",
|
|
||||||
"2nd.OnEnvironmentsSetUpEnd",
|
|
||||||
"1st.OnEnvironmentsSetUpEnd",
|
|
||||||
"1st.OnTestCaseStart",
|
|
||||||
"2nd.OnTestCaseStart",
|
|
||||||
"ListenerTest::SetUpTestCase",
|
|
||||||
"1st.OnTestStart",
|
|
||||||
"2nd.OnTestStart",
|
|
||||||
"ListenerTest::SetUp",
|
|
||||||
"ListenerTest::* Test Body",
|
|
||||||
"1st.OnTestPartResult",
|
|
||||||
"2nd.OnTestPartResult",
|
|
||||||
"ListenerTest::TearDown",
|
|
||||||
"2nd.OnTestEnd",
|
|
||||||
"1st.OnTestEnd",
|
|
||||||
"1st.OnTestStart",
|
|
||||||
"2nd.OnTestStart",
|
|
||||||
"ListenerTest::SetUp",
|
|
||||||
"ListenerTest::* Test Body",
|
|
||||||
"1st.OnTestPartResult",
|
|
||||||
"2nd.OnTestPartResult",
|
|
||||||
"ListenerTest::TearDown",
|
|
||||||
"2nd.OnTestEnd",
|
|
||||||
"1st.OnTestEnd",
|
|
||||||
"ListenerTest::TearDownTestCase",
|
|
||||||
"2nd.OnTestCaseEnd",
|
|
||||||
"1st.OnTestCaseEnd",
|
|
||||||
"1st.OnEnvironmentsTearDownStart",
|
|
||||||
"2nd.OnEnvironmentsTearDownStart",
|
|
||||||
"Environment::TearDown",
|
|
||||||
"2nd.OnEnvironmentsTearDownEnd",
|
|
||||||
"1st.OnEnvironmentsTearDownEnd",
|
|
||||||
"2nd.OnTestIterationEnd(1)",
|
|
||||||
"1st.OnTestIterationEnd(1)",
|
|
||||||
"2nd.OnTestProgramEnd",
|
|
||||||
"1st.OnTestProgramEnd"
|
|
||||||
};
|
|
||||||
VerifyResults(events,
|
|
||||||
expected_events,
|
|
||||||
sizeof(expected_events)/sizeof(expected_events[0]));
|
|
||||||
|
|
||||||
// We need to check manually for ad hoc test failures that happen after
|
|
||||||
// RUN_ALL_TESTS finishes.
|
|
||||||
if (UnitTest::GetInstance()->Failed())
|
|
||||||
ret_val = 1;
|
|
||||||
|
|
||||||
return ret_val;
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue