Merge branch 'master' into fix-1764_CMake-errors-in-googlemock
This commit is contained in:
commit
ebb2fca51a
@ -20,8 +20,7 @@ instructions for how to sign and return it. Once we receive it, we'll be able to
|
|||||||
accept your pull requests.
|
accept your pull requests.
|
||||||
|
|
||||||
## Are you a Googler?
|
## Are you a Googler?
|
||||||
If you are a Googler, please create an internal change and
|
If you are a Googler, you can either create an internal change or work on GitHub directly.
|
||||||
have it reviewed and submitted. The maintainers will normally be in position to upstream the changes.
|
|
||||||
|
|
||||||
|
|
||||||
## Contributing A Patch
|
## Contributing A Patch
|
||||||
|
@ -2602,16 +2602,20 @@ class PropertyMatcher {
|
|||||||
|
|
||||||
// Type traits specifying various features of different functors for ResultOf.
|
// Type traits specifying various features of different functors for ResultOf.
|
||||||
// The default template specifies features for functor objects.
|
// The default template specifies features for functor objects.
|
||||||
// Functor classes have to typedef argument_type and result_type
|
|
||||||
// to be compatible with ResultOf.
|
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
struct CallableTraits {
|
struct CallableTraits {
|
||||||
typedef typename Functor::result_type ResultType;
|
|
||||||
typedef Functor StorageType;
|
typedef Functor StorageType;
|
||||||
|
|
||||||
static void CheckIsValid(Functor /* functor */) {}
|
static void CheckIsValid(Functor /* functor */) {}
|
||||||
|
|
||||||
|
#if GTEST_LANG_CXX11
|
||||||
|
template <typename T>
|
||||||
|
static auto Invoke(Functor f, T arg) -> decltype(f(arg)) { return f(arg); }
|
||||||
|
#else
|
||||||
|
typedef typename Functor::result_type ResultType;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static ResultType Invoke(Functor f, T arg) { return f(arg); }
|
static ResultType Invoke(Functor f, T arg) { return f(arg); }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specialization for function pointers.
|
// Specialization for function pointers.
|
||||||
@ -2632,13 +2636,11 @@ struct CallableTraits<ResType(*)(ArgType)> {
|
|||||||
|
|
||||||
// Implements the ResultOf() matcher for matching a return value of a
|
// Implements the ResultOf() matcher for matching a return value of a
|
||||||
// unary function of an object.
|
// unary function of an object.
|
||||||
template <typename Callable>
|
template <typename Callable, typename InnerMatcher>
|
||||||
class ResultOfMatcher {
|
class ResultOfMatcher {
|
||||||
public:
|
public:
|
||||||
typedef typename CallableTraits<Callable>::ResultType ResultType;
|
ResultOfMatcher(Callable callable, InnerMatcher matcher)
|
||||||
|
: callable_(internal::move(callable)), matcher_(internal::move(matcher)) {
|
||||||
ResultOfMatcher(Callable callable, const Matcher<ResultType>& matcher)
|
|
||||||
: callable_(callable), matcher_(matcher) {
|
|
||||||
CallableTraits<Callable>::CheckIsValid(callable_);
|
CallableTraits<Callable>::CheckIsValid(callable_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2652,9 +2654,17 @@ class ResultOfMatcher {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Impl : public MatcherInterface<T> {
|
class Impl : public MatcherInterface<T> {
|
||||||
|
#if GTEST_LANG_CXX11
|
||||||
|
using ResultType = decltype(CallableTraits<Callable>::template Invoke<T>(
|
||||||
|
std::declval<CallableStorageType>(), std::declval<T>()));
|
||||||
|
#else
|
||||||
|
typedef typename CallableTraits<Callable>::ResultType ResultType;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Impl(CallableStorageType callable, const Matcher<ResultType>& matcher)
|
template <typename M>
|
||||||
: callable_(callable), matcher_(matcher) {}
|
Impl(const CallableStorageType& callable, const M& matcher)
|
||||||
|
: callable_(callable), matcher_(MatcherCast<ResultType>(matcher)) {}
|
||||||
|
|
||||||
virtual void DescribeTo(::std::ostream* os) const {
|
virtual void DescribeTo(::std::ostream* os) const {
|
||||||
*os << "is mapped by the given callable to a value that ";
|
*os << "is mapped by the given callable to a value that ";
|
||||||
@ -2668,8 +2678,10 @@ class ResultOfMatcher {
|
|||||||
|
|
||||||
virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const {
|
virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const {
|
||||||
*listener << "which is mapped by the given callable to ";
|
*listener << "which is mapped by the given callable to ";
|
||||||
// Cannot pass the return value (for example, int) to
|
// Cannot pass the return value directly to MatchPrintAndExplain, which
|
||||||
// MatchPrintAndExplain, which takes a non-const reference as argument.
|
// takes a non-const reference as argument.
|
||||||
|
// Also, specifying template argument explicitly is needed because T could
|
||||||
|
// be a non-const reference (e.g. Matcher<Uncopyable&>).
|
||||||
ResultType result =
|
ResultType result =
|
||||||
CallableTraits<Callable>::template Invoke<T>(callable_, obj);
|
CallableTraits<Callable>::template Invoke<T>(callable_, obj);
|
||||||
return MatchPrintAndExplain(result, matcher_, listener);
|
return MatchPrintAndExplain(result, matcher_, listener);
|
||||||
@ -2679,7 +2691,7 @@ class ResultOfMatcher {
|
|||||||
// Functors often define operator() as non-const method even though
|
// Functors often define operator() as non-const method even though
|
||||||
// they are actually stateless. But we need to use them even when
|
// they are actually stateless. But we need to use them even when
|
||||||
// 'this' is a const pointer. It's the user's responsibility not to
|
// 'this' is a const pointer. It's the user's responsibility not to
|
||||||
// use stateful callables with ResultOf(), which does't guarantee
|
// use stateful callables with ResultOf(), which doesn't guarantee
|
||||||
// how many times the callable will be invoked.
|
// how many times the callable will be invoked.
|
||||||
mutable CallableStorageType callable_;
|
mutable CallableStorageType callable_;
|
||||||
const Matcher<ResultType> matcher_;
|
const Matcher<ResultType> matcher_;
|
||||||
@ -2688,7 +2700,7 @@ class ResultOfMatcher {
|
|||||||
}; // class Impl
|
}; // class Impl
|
||||||
|
|
||||||
const CallableStorageType callable_;
|
const CallableStorageType callable_;
|
||||||
const Matcher<ResultType> matcher_;
|
const InnerMatcher matcher_;
|
||||||
|
|
||||||
GTEST_DISALLOW_ASSIGN_(ResultOfMatcher);
|
GTEST_DISALLOW_ASSIGN_(ResultOfMatcher);
|
||||||
};
|
};
|
||||||
@ -4554,26 +4566,15 @@ Property(const std::string& property_name,
|
|||||||
// For example,
|
// For example,
|
||||||
// ResultOf(f, StartsWith("hi"))
|
// ResultOf(f, StartsWith("hi"))
|
||||||
// matches a Foo object x iff f(x) starts with "hi".
|
// matches a Foo object x iff f(x) starts with "hi".
|
||||||
// callable parameter can be a function, function pointer, or a functor.
|
// `callable` parameter can be a function, function pointer, or a functor. It is
|
||||||
// Callable has to satisfy the following conditions:
|
// required to keep no state affecting the results of the calls on it and make
|
||||||
// * It is required to keep no state affecting the results of
|
// no assumptions about how many calls will be made. Any state it keeps must be
|
||||||
// the calls on it and make no assumptions about how many calls
|
// protected from the concurrent access.
|
||||||
// will be made. Any state it keeps must be protected from the
|
template <typename Callable, typename InnerMatcher>
|
||||||
// concurrent access.
|
internal::ResultOfMatcher<Callable, InnerMatcher> ResultOf(
|
||||||
// * If it is a function object, it has to define type result_type.
|
Callable callable, InnerMatcher matcher) {
|
||||||
// We recommend deriving your functor classes from std::unary_function.
|
return internal::ResultOfMatcher<Callable, InnerMatcher>(
|
||||||
//
|
internal::move(callable), internal::move(matcher));
|
||||||
template <typename Callable, typename ResultOfMatcher>
|
|
||||||
internal::ResultOfMatcher<Callable> ResultOf(
|
|
||||||
Callable callable, const ResultOfMatcher& matcher) {
|
|
||||||
return internal::ResultOfMatcher<Callable>(
|
|
||||||
callable,
|
|
||||||
MatcherCast<typename internal::CallableTraits<Callable>::ResultType>(
|
|
||||||
matcher));
|
|
||||||
// The call to MatcherCast() is required for supporting inner
|
|
||||||
// matchers of compatible types. For example, it allows
|
|
||||||
// ResultOf(Function, m)
|
|
||||||
// to compile where Function() returns an int32 and m is a matcher for int64.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String matchers.
|
// String matchers.
|
||||||
|
@ -4597,6 +4597,7 @@ struct PolymorphicFunctor {
|
|||||||
typedef int result_type;
|
typedef int result_type;
|
||||||
int operator()(int n) { return n; }
|
int operator()(int n) { return n; }
|
||||||
int operator()(const char* s) { return static_cast<int>(strlen(s)); }
|
int operator()(const char* s) { return static_cast<int>(strlen(s)); }
|
||||||
|
std::string operator()(int *p) { return p ? "good ptr" : "null"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(ResultOfTest, WorksForPolymorphicFunctors) {
|
TEST(ResultOfTest, WorksForPolymorphicFunctors) {
|
||||||
@ -4611,6 +4612,23 @@ TEST(ResultOfTest, WorksForPolymorphicFunctors) {
|
|||||||
EXPECT_FALSE(matcher_string.Matches("shrt"));
|
EXPECT_FALSE(matcher_string.Matches("shrt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if GTEST_LANG_CXX11
|
||||||
|
TEST(ResultOfTest, WorksForPolymorphicFunctorsIgnoringResultType) {
|
||||||
|
Matcher<int*> matcher = ResultOf(PolymorphicFunctor(), "good ptr");
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
EXPECT_TRUE(matcher.Matches(&n));
|
||||||
|
EXPECT_FALSE(matcher.Matches(nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ResultOfTest, WorksForLambdas) {
|
||||||
|
Matcher<int> matcher =
|
||||||
|
ResultOf([](int str_len) { return std::string(str_len, 'x'); }, "xxx");
|
||||||
|
EXPECT_TRUE(matcher.Matches(3));
|
||||||
|
EXPECT_FALSE(matcher.Matches(1));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const int* ReferencingFunction(const int& n) { return &n; }
|
const int* ReferencingFunction(const int& n) { return &n; }
|
||||||
|
|
||||||
struct ReferencingFunctor {
|
struct ReferencingFunctor {
|
||||||
|
@ -194,6 +194,21 @@ const char kStackTraceMarker[] = "\nStack trace:\n";
|
|||||||
// specified on the command line.
|
// specified on the command line.
|
||||||
bool g_help_flag = false;
|
bool g_help_flag = false;
|
||||||
|
|
||||||
|
// Utilty function to Open File for Writing
|
||||||
|
static FILE* OpenFileForWriting(const std::string& output_file) {
|
||||||
|
FILE* fileout = NULL;
|
||||||
|
FilePath output_file_path(output_file);
|
||||||
|
FilePath output_dir(output_file_path.RemoveFileName());
|
||||||
|
|
||||||
|
if (output_dir.CreateDirectoriesRecursively()) {
|
||||||
|
fileout = posix::FOpen(output_file.c_str(), "w");
|
||||||
|
}
|
||||||
|
if (fileout == NULL) {
|
||||||
|
GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\"";
|
||||||
|
}
|
||||||
|
return fileout;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY
|
// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY
|
||||||
@ -454,6 +469,7 @@ std::string UnitTestOptions::GetOutputFormat() {
|
|||||||
|
|
||||||
// Returns the name of the requested output file, or the default if none
|
// Returns the name of the requested output file, or the default if none
|
||||||
// was explicitly specified.
|
// was explicitly specified.
|
||||||
|
// FIXME Remove GetAbsolutePathToOutputFile checking gtest_output_flag == NULL
|
||||||
std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
|
std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
|
||||||
const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
|
const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
|
||||||
if (gtest_output_flag == NULL)
|
if (gtest_output_flag == NULL)
|
||||||
@ -2130,13 +2146,8 @@ static const char* const kReservedTestSuiteAttributes[] = {
|
|||||||
|
|
||||||
// The list of reserved attributes used in the <testcase> element of XML output.
|
// The list of reserved attributes used in the <testcase> element of XML output.
|
||||||
static const char* const kReservedTestCaseAttributes[] = {
|
static const char* const kReservedTestCaseAttributes[] = {
|
||||||
"classname",
|
"classname", "name", "status", "time",
|
||||||
"name",
|
"type_param", "value_param", "file", "line"};
|
||||||
"status",
|
|
||||||
"time",
|
|
||||||
"type_param",
|
|
||||||
"value_param"
|
|
||||||
};
|
|
||||||
|
|
||||||
template <int kSize>
|
template <int kSize>
|
||||||
std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
|
std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
|
||||||
@ -3414,6 +3425,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener {
|
|||||||
explicit XmlUnitTestResultPrinter(const char* output_file);
|
explicit XmlUnitTestResultPrinter(const char* output_file);
|
||||||
|
|
||||||
virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
|
virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
|
||||||
|
void ListTestsMatchingFilter(const std::vector<TestCase*>& test_cases);
|
||||||
|
|
||||||
|
// Prints an XML summary of all unit tests.
|
||||||
|
static void PrintXmlTestsList(std::ostream* stream,
|
||||||
|
const std::vector<TestCase*>& test_cases);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Is c a whitespace character that is normalized to a space character
|
// Is c a whitespace character that is normalized to a space character
|
||||||
@ -3497,33 +3513,22 @@ XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
|
|||||||
// Called after the unit test ends.
|
// Called after the unit test ends.
|
||||||
void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
|
void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
|
||||||
int /*iteration*/) {
|
int /*iteration*/) {
|
||||||
FILE* xmlout = NULL;
|
FILE* xmlout = OpenFileForWriting(output_file_);
|
||||||
FilePath output_file(output_file_);
|
|
||||||
FilePath output_dir(output_file.RemoveFileName());
|
|
||||||
|
|
||||||
if (output_dir.CreateDirectoriesRecursively()) {
|
|
||||||
xmlout = posix::FOpen(output_file_.c_str(), "w");
|
|
||||||
}
|
|
||||||
if (xmlout == NULL) {
|
|
||||||
// FIXME: report the reason of the failure.
|
|
||||||
//
|
|
||||||
// We don't do it for now as:
|
|
||||||
//
|
|
||||||
// 1. There is no urgent need for it.
|
|
||||||
// 2. It's a bit involved to make the errno variable thread-safe on
|
|
||||||
// all three operating systems (Linux, Windows, and Mac OS).
|
|
||||||
// 3. To interpret the meaning of errno in a thread-safe way,
|
|
||||||
// we need the strerror_r() function, which is not available on
|
|
||||||
// Windows.
|
|
||||||
|
|
||||||
GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file_ << "\"";
|
|
||||||
}
|
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
PrintXmlUnitTest(&stream, unit_test);
|
PrintXmlUnitTest(&stream, unit_test);
|
||||||
fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
|
fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
|
||||||
fclose(xmlout);
|
fclose(xmlout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XmlUnitTestResultPrinter::ListTestsMatchingFilter(
|
||||||
|
const std::vector<TestCase*>& test_cases) {
|
||||||
|
FILE* xmlout = OpenFileForWriting(output_file_);
|
||||||
|
std::stringstream stream;
|
||||||
|
PrintXmlTestsList(&stream, test_cases);
|
||||||
|
fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
|
||||||
|
fclose(xmlout);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns an XML-escaped copy of the input string str. If is_attribute
|
// Returns an XML-escaped copy of the input string str. If is_attribute
|
||||||
// is true, the text is meant to appear as an attribute value, and
|
// is true, the text is meant to appear as an attribute value, and
|
||||||
// normalizable whitespace is preserved by replacing it with character
|
// normalizable whitespace is preserved by replacing it with character
|
||||||
@ -3706,6 +3711,13 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
|
|||||||
if (test_info.type_param() != NULL) {
|
if (test_info.type_param() != NULL) {
|
||||||
OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param());
|
OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param());
|
||||||
}
|
}
|
||||||
|
if (GTEST_FLAG(list_tests)) {
|
||||||
|
OutputXmlAttribute(stream, kTestcase, "file", test_info.file());
|
||||||
|
OutputXmlAttribute(stream, kTestcase, "line",
|
||||||
|
StreamableToString(test_info.line()));
|
||||||
|
*stream << " />\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
OutputXmlAttribute(stream, kTestcase, "status",
|
OutputXmlAttribute(stream, kTestcase, "status",
|
||||||
test_info.should_run() ? "run" : "notrun");
|
test_info.should_run() ? "run" : "notrun");
|
||||||
@ -3752,17 +3764,18 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream,
|
|||||||
OutputXmlAttribute(stream, kTestsuite, "name", test_case.name());
|
OutputXmlAttribute(stream, kTestsuite, "name", test_case.name());
|
||||||
OutputXmlAttribute(stream, kTestsuite, "tests",
|
OutputXmlAttribute(stream, kTestsuite, "tests",
|
||||||
StreamableToString(test_case.reportable_test_count()));
|
StreamableToString(test_case.reportable_test_count()));
|
||||||
OutputXmlAttribute(stream, kTestsuite, "failures",
|
if (!GTEST_FLAG(list_tests)) {
|
||||||
StreamableToString(test_case.failed_test_count()));
|
OutputXmlAttribute(stream, kTestsuite, "failures",
|
||||||
OutputXmlAttribute(
|
StreamableToString(test_case.failed_test_count()));
|
||||||
stream, kTestsuite, "disabled",
|
OutputXmlAttribute(
|
||||||
StreamableToString(test_case.reportable_disabled_test_count()));
|
stream, kTestsuite, "disabled",
|
||||||
OutputXmlAttribute(stream, kTestsuite, "errors", "0");
|
StreamableToString(test_case.reportable_disabled_test_count()));
|
||||||
OutputXmlAttribute(stream, kTestsuite, "time",
|
OutputXmlAttribute(stream, kTestsuite, "errors", "0");
|
||||||
FormatTimeInMillisAsSeconds(test_case.elapsed_time()));
|
OutputXmlAttribute(stream, kTestsuite, "time",
|
||||||
*stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result())
|
FormatTimeInMillisAsSeconds(test_case.elapsed_time()));
|
||||||
<< ">\n";
|
*stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result());
|
||||||
|
}
|
||||||
|
*stream << ">\n";
|
||||||
for (int i = 0; i < test_case.total_test_count(); ++i) {
|
for (int i = 0; i < test_case.total_test_count(); ++i) {
|
||||||
if (test_case.GetTestInfo(i)->is_reportable())
|
if (test_case.GetTestInfo(i)->is_reportable())
|
||||||
OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i));
|
OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i));
|
||||||
@ -3808,6 +3821,28 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
|
|||||||
*stream << "</" << kTestsuites << ">\n";
|
*stream << "</" << kTestsuites << ">\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XmlUnitTestResultPrinter::PrintXmlTestsList(
|
||||||
|
std::ostream* stream, const std::vector<TestCase*>& test_cases) {
|
||||||
|
const std::string kTestsuites = "testsuites";
|
||||||
|
|
||||||
|
*stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||||
|
*stream << "<" << kTestsuites;
|
||||||
|
|
||||||
|
int total_tests = 0;
|
||||||
|
for (size_t i = 0; i < test_cases.size(); ++i) {
|
||||||
|
total_tests += test_cases[i]->total_test_count();
|
||||||
|
}
|
||||||
|
OutputXmlAttribute(stream, kTestsuites, "tests",
|
||||||
|
StreamableToString(total_tests));
|
||||||
|
OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
|
||||||
|
*stream << ">\n";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < test_cases.size(); ++i) {
|
||||||
|
PrintXmlTestCase(stream, *test_cases[i]);
|
||||||
|
}
|
||||||
|
*stream << "</" << kTestsuites << ">\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Produces a string representing the test properties in a result as space
|
// Produces a string representing the test properties in a result as space
|
||||||
// delimited XML attributes based on the property key="value" pairs.
|
// delimited XML attributes based on the property key="value" pairs.
|
||||||
std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
|
std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
|
||||||
@ -3843,7 +3878,6 @@ void XmlUnitTestResultPrinter::OutputXmlTestProperties(
|
|||||||
|
|
||||||
// End XmlUnitTestResultPrinter
|
// End XmlUnitTestResultPrinter
|
||||||
|
|
||||||
|
|
||||||
// This class generates an JSON output file.
|
// This class generates an JSON output file.
|
||||||
class JsonUnitTestResultPrinter : public EmptyTestEventListener {
|
class JsonUnitTestResultPrinter : public EmptyTestEventListener {
|
||||||
public:
|
public:
|
||||||
@ -3851,6 +3885,10 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener {
|
|||||||
|
|
||||||
virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
|
virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
|
||||||
|
|
||||||
|
// Prints an JSON summary of all unit tests.
|
||||||
|
static void PrintJsonTestList(::std::ostream* stream,
|
||||||
|
const std::vector<TestCase*>& test_cases);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Returns an JSON-escaped copy of the input string str.
|
// Returns an JSON-escaped copy of the input string str.
|
||||||
static std::string EscapeJson(const std::string& str);
|
static std::string EscapeJson(const std::string& str);
|
||||||
@ -3904,27 +3942,7 @@ JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file)
|
|||||||
|
|
||||||
void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
|
void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
|
||||||
int /*iteration*/) {
|
int /*iteration*/) {
|
||||||
FILE* jsonout = NULL;
|
FILE* jsonout = OpenFileForWriting(output_file_);
|
||||||
FilePath output_file(output_file_);
|
|
||||||
FilePath output_dir(output_file.RemoveFileName());
|
|
||||||
|
|
||||||
if (output_dir.CreateDirectoriesRecursively()) {
|
|
||||||
jsonout = posix::FOpen(output_file_.c_str(), "w");
|
|
||||||
}
|
|
||||||
if (jsonout == NULL) {
|
|
||||||
// FIXME: report the reason of the failure.
|
|
||||||
//
|
|
||||||
// We don't do it for now as:
|
|
||||||
//
|
|
||||||
// 1. There is no urgent need for it.
|
|
||||||
// 2. It's a bit involved to make the errno variable thread-safe on
|
|
||||||
// all three operating systems (Linux, Windows, and Mac OS).
|
|
||||||
// 3. To interpret the meaning of errno in a thread-safe way,
|
|
||||||
// we need the strerror_r() function, which is not available on
|
|
||||||
// Windows.
|
|
||||||
GTEST_LOG_(FATAL) << "Unable to open file \""
|
|
||||||
<< output_file_ << "\"";
|
|
||||||
}
|
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
PrintJsonUnitTest(&stream, unit_test);
|
PrintJsonUnitTest(&stream, unit_test);
|
||||||
fprintf(jsonout, "%s", StringStreamToString(&stream).c_str());
|
fprintf(jsonout, "%s", StringStreamToString(&stream).c_str());
|
||||||
@ -4059,6 +4077,12 @@ void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream,
|
|||||||
OutputJsonKey(stream, kTestcase, "type_param", test_info.type_param(),
|
OutputJsonKey(stream, kTestcase, "type_param", test_info.type_param(),
|
||||||
kIndent);
|
kIndent);
|
||||||
}
|
}
|
||||||
|
if (GTEST_FLAG(list_tests)) {
|
||||||
|
OutputJsonKey(stream, kTestcase, "file", test_info.file(), kIndent);
|
||||||
|
OutputJsonKey(stream, kTestcase, "line", test_info.line(), kIndent, false);
|
||||||
|
*stream << "\n" << Indent(8) << "}";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
OutputJsonKey(stream, kTestcase, "status",
|
OutputJsonKey(stream, kTestcase, "status",
|
||||||
test_info.should_run() ? "RUN" : "NOTRUN", kIndent);
|
test_info.should_run() ? "RUN" : "NOTRUN", kIndent);
|
||||||
@ -4101,16 +4125,18 @@ void JsonUnitTestResultPrinter::PrintJsonTestCase(std::ostream* stream,
|
|||||||
OutputJsonKey(stream, kTestsuite, "name", test_case.name(), kIndent);
|
OutputJsonKey(stream, kTestsuite, "name", test_case.name(), kIndent);
|
||||||
OutputJsonKey(stream, kTestsuite, "tests", test_case.reportable_test_count(),
|
OutputJsonKey(stream, kTestsuite, "tests", test_case.reportable_test_count(),
|
||||||
kIndent);
|
kIndent);
|
||||||
OutputJsonKey(stream, kTestsuite, "failures", test_case.failed_test_count(),
|
if (!GTEST_FLAG(list_tests)) {
|
||||||
kIndent);
|
OutputJsonKey(stream, kTestsuite, "failures", test_case.failed_test_count(),
|
||||||
OutputJsonKey(stream, kTestsuite, "disabled",
|
kIndent);
|
||||||
test_case.reportable_disabled_test_count(), kIndent);
|
OutputJsonKey(stream, kTestsuite, "disabled",
|
||||||
OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent);
|
test_case.reportable_disabled_test_count(), kIndent);
|
||||||
OutputJsonKey(stream, kTestsuite, "time",
|
OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent);
|
||||||
FormatTimeInMillisAsDuration(test_case.elapsed_time()), kIndent,
|
OutputJsonKey(stream, kTestsuite, "time",
|
||||||
false);
|
FormatTimeInMillisAsDuration(test_case.elapsed_time()),
|
||||||
*stream << TestPropertiesAsJson(test_case.ad_hoc_test_result(), kIndent)
|
kIndent, false);
|
||||||
<< ",\n";
|
*stream << TestPropertiesAsJson(test_case.ad_hoc_test_result(), kIndent)
|
||||||
|
<< ",\n";
|
||||||
|
}
|
||||||
|
|
||||||
*stream << kIndent << "\"" << kTestsuite << "\": [\n";
|
*stream << kIndent << "\"" << kTestsuite << "\": [\n";
|
||||||
|
|
||||||
@ -4174,6 +4200,31 @@ void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream,
|
|||||||
*stream << "\n" << kIndent << "]\n" << "}\n";
|
*stream << "\n" << kIndent << "]\n" << "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JsonUnitTestResultPrinter::PrintJsonTestList(
|
||||||
|
std::ostream* stream, const std::vector<TestCase*>& test_cases) {
|
||||||
|
const std::string kTestsuites = "testsuites";
|
||||||
|
const std::string kIndent = Indent(2);
|
||||||
|
*stream << "{\n";
|
||||||
|
int total_tests = 0;
|
||||||
|
for (size_t i = 0; i < test_cases.size(); ++i) {
|
||||||
|
total_tests += test_cases[i]->total_test_count();
|
||||||
|
}
|
||||||
|
OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent);
|
||||||
|
|
||||||
|
OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent);
|
||||||
|
*stream << kIndent << "\"" << kTestsuites << "\": [\n";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < test_cases.size(); ++i) {
|
||||||
|
if (i != 0) {
|
||||||
|
*stream << ",\n";
|
||||||
|
}
|
||||||
|
PrintJsonTestCase(stream, *test_cases[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*stream << "\n"
|
||||||
|
<< kIndent << "]\n"
|
||||||
|
<< "}\n";
|
||||||
|
}
|
||||||
// Produces a string representing the test properties in a result as
|
// Produces a string representing the test properties in a result as
|
||||||
// a JSON dictionary.
|
// a JSON dictionary.
|
||||||
std::string JsonUnitTestResultPrinter::TestPropertiesAsJson(
|
std::string JsonUnitTestResultPrinter::TestPropertiesAsJson(
|
||||||
@ -5394,6 +5445,23 @@ void UnitTestImpl::ListTestsMatchingFilter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
const std::string& output_format = UnitTestOptions::GetOutputFormat();
|
||||||
|
if (output_format == "xml" || output_format == "json") {
|
||||||
|
FILE* fileout = OpenFileForWriting(
|
||||||
|
UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
|
||||||
|
std::stringstream stream;
|
||||||
|
if (output_format == "xml") {
|
||||||
|
XmlUnitTestResultPrinter(
|
||||||
|
UnitTestOptions::GetAbsolutePathToOutputFile().c_str())
|
||||||
|
.PrintXmlTestsList(&stream, test_cases_);
|
||||||
|
} else if (output_format == "json") {
|
||||||
|
JsonUnitTestResultPrinter(
|
||||||
|
UnitTestOptions::GetAbsolutePathToOutputFile().c_str())
|
||||||
|
.PrintJsonTestList(&stream, test_cases_);
|
||||||
|
}
|
||||||
|
fprintf(fileout, "%s", StringStreamToString(&stream).c_str());
|
||||||
|
fclose(fileout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the OS stack trace getter.
|
// Sets the OS stack trace getter.
|
||||||
|
141
googletest/test/gtest_list_output_unittest.py
Normal file
141
googletest/test/gtest_list_output_unittest.py
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2006, 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.
|
||||||
|
"""Unit test for Google Test's --gtest_list_tests flag.
|
||||||
|
|
||||||
|
A user can ask Google Test to list all tests by specifying the
|
||||||
|
--gtest_list_tests flag. If output is requested, via --gtest_output=xml
|
||||||
|
or --gtest_output=json, the tests are listed, with extra information in the
|
||||||
|
output file.
|
||||||
|
This script tests such functionality by invoking gtest_list_output_unittest_
|
||||||
|
(a program written with Google Test) the command line flags.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import gtest_test_utils
|
||||||
|
|
||||||
|
GTEST_LIST_TESTS_FLAG = '--gtest_list_tests'
|
||||||
|
GTEST_OUTPUT_FLAG = '--gtest_output'
|
||||||
|
|
||||||
|
EXPECTED_XML = """<\?xml version="1.0" encoding="UTF-8"\?>
|
||||||
|
<testsuites tests="2" name="AllTests">
|
||||||
|
<testsuite name="FooTest" tests="2">
|
||||||
|
<testcase name="Test1" file=".*gtest_list_output_unittest_.cc" line="43" />
|
||||||
|
<testcase name="Test2" file=".*gtest_list_output_unittest_.cc" line="45" />
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXPECTED_JSON = """{
|
||||||
|
"tests": 2,
|
||||||
|
"name": "AllTests",
|
||||||
|
"testsuites": \[
|
||||||
|
{
|
||||||
|
"name": "FooTest",
|
||||||
|
"tests": 2,
|
||||||
|
"testsuite": \[
|
||||||
|
{
|
||||||
|
"name": "Test1",
|
||||||
|
"file": ".*gtest_list_output_unittest_.cc",
|
||||||
|
"line": 43
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Test2",
|
||||||
|
"file": ".*gtest_list_output_unittest_.cc",
|
||||||
|
"line": 45
|
||||||
|
}
|
||||||
|
\]
|
||||||
|
}
|
||||||
|
\]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class GTestListTestsOutputUnitTest(gtest_test_utils.TestCase):
|
||||||
|
"""Unit test for Google Test's list tests with output to file functionality.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def testXml(self):
|
||||||
|
"""Verifies XML output for listing tests in a Google Test binary.
|
||||||
|
|
||||||
|
Runs a test program that generates an empty XML output, and
|
||||||
|
tests that the XML output is expected.
|
||||||
|
"""
|
||||||
|
self._TestOutput('xml', EXPECTED_XML)
|
||||||
|
|
||||||
|
def testJSON(self):
|
||||||
|
"""Verifies XML output for listing tests in a Google Test binary.
|
||||||
|
|
||||||
|
Runs a test program that generates an empty XML output, and
|
||||||
|
tests that the XML output is expected.
|
||||||
|
"""
|
||||||
|
self._TestOutput('json', EXPECTED_JSON)
|
||||||
|
|
||||||
|
def _GetOutput(self, out_format):
|
||||||
|
file_path = os.path.join(gtest_test_utils.GetTempDir(),
|
||||||
|
'test_out.' + out_format)
|
||||||
|
gtest_prog_path = gtest_test_utils.GetTestExecutablePath(
|
||||||
|
'gtest_list_output_unittest_')
|
||||||
|
|
||||||
|
command = ([
|
||||||
|
gtest_prog_path,
|
||||||
|
'%s=%s:%s' % (GTEST_OUTPUT_FLAG, out_format, file_path),
|
||||||
|
'--gtest_list_tests'
|
||||||
|
])
|
||||||
|
environ_copy = os.environ.copy()
|
||||||
|
p = gtest_test_utils.Subprocess(
|
||||||
|
command, env=environ_copy, working_dir=gtest_test_utils.GetTempDir())
|
||||||
|
|
||||||
|
self.assert_(p.exited)
|
||||||
|
self.assertEquals(0, p.exit_code)
|
||||||
|
with open(file_path) as f:
|
||||||
|
result = f.read()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _TestOutput(self, test_format, expected_output):
|
||||||
|
actual = self._GetOutput(test_format)
|
||||||
|
actual_lines = actual.splitlines()
|
||||||
|
expected_lines = expected_output.splitlines()
|
||||||
|
line_count = 0
|
||||||
|
for actual_line in actual_lines:
|
||||||
|
expected_line = expected_lines[line_count]
|
||||||
|
expected_line_re = re.compile(expected_line.strip())
|
||||||
|
self.assert_(
|
||||||
|
expected_line_re.match(actual_line.strip()),
|
||||||
|
('actual output of "%s",\n'
|
||||||
|
'which does not match expected regex of "%s"\n'
|
||||||
|
'on line %d' % (actual, expected_output, line_count)))
|
||||||
|
line_count = line_count + 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
os.environ['GTEST_STACK_TRACE_DEPTH'] = '1'
|
||||||
|
gtest_test_utils.Main()
|
51
googletest/test/gtest_list_output_unittest_.cc
Normal file
51
googletest/test/gtest_list_output_unittest_.cc
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2018, 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: david.schuldenfrei@gmail.com (David Schuldenfrei)
|
||||||
|
|
||||||
|
// Unit test for Google Test's --gtest_list_tests and --gtest_output flag.
|
||||||
|
//
|
||||||
|
// A user can ask Google Test to list all tests that will run,
|
||||||
|
// and have the output saved in a Json/Xml file.
|
||||||
|
// The tests will not be run after listing.
|
||||||
|
//
|
||||||
|
// This program will be invoked from a Python unit test.
|
||||||
|
// Don't run it directly.
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
TEST(FooTest, Test1) {}
|
||||||
|
|
||||||
|
TEST(FooTest, Test2) {}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
@ -2090,8 +2090,8 @@ TEST_F(UnitTestRecordPropertyTest,
|
|||||||
AddRecordWithReservedKeysGeneratesCorrectPropertyList) {
|
AddRecordWithReservedKeysGeneratesCorrectPropertyList) {
|
||||||
EXPECT_NONFATAL_FAILURE(
|
EXPECT_NONFATAL_FAILURE(
|
||||||
Test::RecordProperty("name", "1"),
|
Test::RecordProperty("name", "1"),
|
||||||
"'classname', 'name', 'status', 'time', 'type_param', and 'value_param'"
|
"'classname', 'name', 'status', 'time', 'type_param', 'value_param',"
|
||||||
" are reserved");
|
" 'file', and 'line' are reserved");
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnitTestRecordPropertyTestEnvironment : public Environment {
|
class UnitTestRecordPropertyTestEnvironment : public Environment {
|
||||||
|
Loading…
Reference in New Issue
Block a user