diff options
author | Gennadiy Civil <gennadiycivil@users.noreply.github.com> | 2018-08-27 17:25:45 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-27 17:25:45 (GMT) |
commit | ebb2fca51a2b868132992d273bb97696bff969b3 (patch) | |
tree | a5825772e31b5b67c484da238f5935664b4864c4 | |
parent | b19292e6b64263992cd049154015a6ef359473ef (diff) | |
parent | 641e7a3752d451d3ea246d1dd1528f6315b87fcf (diff) | |
download | googletest-ebb2fca51a2b868132992d273bb97696bff969b3.zip googletest-ebb2fca51a2b868132992d273bb97696bff969b3.tar.gz googletest-ebb2fca51a2b868132992d273bb97696bff969b3.tar.bz2 |
Merge branch 'master' into fix-1764_CMake-errors-in-googlemockrefs/pull/1769/head
-rw-r--r-- | CONTRIBUTING.md | 3 | ||||
-rw-r--r-- | googlemock/include/gmock/gmock-matchers.h | 69 | ||||
-rw-r--r-- | googlemock/test/gmock-matchers_test.cc | 18 | ||||
-rw-r--r-- | googletest/src/gtest.cc | 210 | ||||
-rw-r--r-- | googletest/test/gtest_list_output_unittest.py | 141 | ||||
-rw-r--r-- | googletest/test/gtest_list_output_unittest_.cc | 51 | ||||
-rw-r--r-- | googletest/test/gtest_unittest.cc | 4 |
7 files changed, 387 insertions, 109 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4dfdd95..846dd8a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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. ## Are you a Googler? -If you are a Googler, please create an internal change and -have it reviewed and submitted. The maintainers will normally be in position to upstream the changes. +If you are a Googler, you can either create an internal change or work on GitHub directly. ## Contributing A Patch diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 3336eff..3975cd0 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -2602,16 +2602,20 @@ class PropertyMatcher { // Type traits specifying various features of different functors for ResultOf. // 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> struct CallableTraits { - typedef typename Functor::result_type ResultType; typedef Functor StorageType; 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> static ResultType Invoke(Functor f, T arg) { return f(arg); } +#endif }; // Specialization for function pointers. @@ -2632,13 +2636,11 @@ struct CallableTraits<ResType(*)(ArgType)> { // Implements the ResultOf() matcher for matching a return value of a // unary function of an object. -template <typename Callable> +template <typename Callable, typename InnerMatcher> class ResultOfMatcher { public: - typedef typename CallableTraits<Callable>::ResultType ResultType; - - ResultOfMatcher(Callable callable, const Matcher<ResultType>& matcher) - : callable_(callable), matcher_(matcher) { + ResultOfMatcher(Callable callable, InnerMatcher matcher) + : callable_(internal::move(callable)), matcher_(internal::move(matcher)) { CallableTraits<Callable>::CheckIsValid(callable_); } @@ -2652,9 +2654,17 @@ class ResultOfMatcher { template <typename 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: - Impl(CallableStorageType callable, const Matcher<ResultType>& matcher) - : callable_(callable), matcher_(matcher) {} + template <typename M> + Impl(const CallableStorageType& callable, const M& matcher) + : callable_(callable), matcher_(MatcherCast<ResultType>(matcher)) {} virtual void DescribeTo(::std::ostream* os) const { *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 { *listener << "which is mapped by the given callable to "; - // Cannot pass the return value (for example, int) to - // MatchPrintAndExplain, which takes a non-const reference as argument. + // Cannot pass the return value directly to MatchPrintAndExplain, which + // 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 = CallableTraits<Callable>::template Invoke<T>(callable_, obj); return MatchPrintAndExplain(result, matcher_, listener); @@ -2679,7 +2691,7 @@ class ResultOfMatcher { // Functors often define operator() as non-const method even though // 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 - // 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. mutable CallableStorageType callable_; const Matcher<ResultType> matcher_; @@ -2688,7 +2700,7 @@ class ResultOfMatcher { }; // class Impl const CallableStorageType callable_; - const Matcher<ResultType> matcher_; + const InnerMatcher matcher_; GTEST_DISALLOW_ASSIGN_(ResultOfMatcher); }; @@ -4554,26 +4566,15 @@ Property(const std::string& property_name, // For example, // ResultOf(f, StartsWith("hi")) // matches a Foo object x iff f(x) starts with "hi". -// callable parameter can be a function, function pointer, or a functor. -// Callable has to satisfy the following conditions: -// * It is required to keep no state affecting the results of -// the calls on it and make no assumptions about how many calls -// will be made. Any state it keeps must be protected from the -// concurrent access. -// * If it is a function object, it has to define type result_type. -// We recommend deriving your functor classes from std::unary_function. -// -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. +// `callable` parameter can be a function, function pointer, or a functor. It is +// required to keep no state affecting the results of the calls on it and make +// no assumptions about how many calls will be made. Any state it keeps must be +// protected from the concurrent access. +template <typename Callable, typename InnerMatcher> +internal::ResultOfMatcher<Callable, InnerMatcher> ResultOf( + Callable callable, InnerMatcher matcher) { + return internal::ResultOfMatcher<Callable, InnerMatcher>( + internal::move(callable), internal::move(matcher)); } // String matchers. diff --git a/googlemock/test/gmock-matchers_test.cc b/googlemock/test/gmock-matchers_test.cc index d08f08f..4697f0b 100644 --- a/googlemock/test/gmock-matchers_test.cc +++ b/googlemock/test/gmock-matchers_test.cc @@ -4597,6 +4597,7 @@ struct PolymorphicFunctor { typedef int result_type; int operator()(int n) { return n; } int operator()(const char* s) { return static_cast<int>(strlen(s)); } + std::string operator()(int *p) { return p ? "good ptr" : "null"; } }; TEST(ResultOfTest, WorksForPolymorphicFunctors) { @@ -4611,6 +4612,23 @@ TEST(ResultOfTest, WorksForPolymorphicFunctors) { 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; } struct ReferencingFunctor { diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index e9127a1..f476044 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -194,6 +194,21 @@ const char kStackTraceMarker[] = "\nStack trace:\n"; // specified on the command line. bool g_help_flag = false; +// Utilty function to Open File for Writing +static FILE* OpenFileForWriting(const std::string& output_file) { + FILE* fileout = 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 // 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 // was explicitly specified. +// FIXME Remove GetAbsolutePathToOutputFile checking gtest_output_flag == NULL std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); 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. static const char* const kReservedTestCaseAttributes[] = { - "classname", - "name", - "status", - "time", - "type_param", - "value_param" -}; + "classname", "name", "status", "time", + "type_param", "value_param", "file", "line"}; template <int 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); 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: // 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. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // 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_ << "\""; - } + FILE* xmlout = OpenFileForWriting(output_file_); std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } +void XmlUnitTestResultPrinter::ListTestsMatchingFilter( + const std::vector<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 // is true, the text is meant to appear as an attribute value, and // 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) { 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", 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, "tests", StreamableToString(test_case.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuite, "errors", "0"); - OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) - << ">\n"; - + if (!GTEST_FLAG(list_tests)) { + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_case.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_case.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()); + } + *stream << ">\n"; for (int i = 0; i < test_case.total_test_count(); ++i) { if (test_case.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); @@ -3808,6 +3821,28 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, *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 // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( @@ -3843,7 +3878,6 @@ void XmlUnitTestResultPrinter::OutputXmlTestProperties( // End XmlUnitTestResultPrinter - // This class generates an JSON output file. class JsonUnitTestResultPrinter : public EmptyTestEventListener { public: @@ -3851,6 +3885,10 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener { 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: // Returns an JSON-escaped copy of the input 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, int /*iteration*/) { - FILE* jsonout = NULL; - 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_ << "\""; - } + FILE* jsonout = OpenFileForWriting(output_file_); std::stringstream stream; PrintJsonUnitTest(&stream, unit_test); 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(), 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", 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, "tests", test_case.reportable_test_count(), kIndent); - OutputJsonKey(stream, kTestsuite, "failures", test_case.failed_test_count(), - kIndent); - OutputJsonKey(stream, kTestsuite, "disabled", - test_case.reportable_disabled_test_count(), kIndent); - OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); - OutputJsonKey(stream, kTestsuite, "time", - FormatTimeInMillisAsDuration(test_case.elapsed_time()), kIndent, - false); - *stream << TestPropertiesAsJson(test_case.ad_hoc_test_result(), kIndent) - << ",\n"; + if (!GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "failures", test_case.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuite, "disabled", + test_case.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(test_case.elapsed_time()), + kIndent, false); + *stream << TestPropertiesAsJson(test_case.ad_hoc_test_result(), kIndent) + << ",\n"; + } *stream << kIndent << "\"" << kTestsuite << "\": [\n"; @@ -4174,6 +4200,31 @@ void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, *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 // a JSON dictionary. std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( @@ -5394,6 +5445,23 @@ void UnitTestImpl::ListTestsMatchingFilter() { } } fflush(stdout); + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml" || output_format == "json") { + FILE* fileout = OpenFileForWriting( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); + std::stringstream stream; + if (output_format == "xml") { + XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintXmlTestsList(&stream, test_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. diff --git a/googletest/test/gtest_list_output_unittest.py b/googletest/test/gtest_list_output_unittest.py new file mode 100644 index 0000000..3bba7ea --- /dev/null +++ b/googletest/test/gtest_list_output_unittest.py @@ -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() diff --git a/googletest/test/gtest_list_output_unittest_.cc b/googletest/test/gtest_list_output_unittest_.cc new file mode 100644 index 0000000..b1c7b4d --- /dev/null +++ b/googletest/test/gtest_list_output_unittest_.cc @@ -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(); +} diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index e1c30f3..f7213fb 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -2090,8 +2090,8 @@ TEST_F(UnitTestRecordPropertyTest, AddRecordWithReservedKeysGeneratesCorrectPropertyList) { EXPECT_NONFATAL_FAILURE( Test::RecordProperty("name", "1"), - "'classname', 'name', 'status', 'time', 'type_param', and 'value_param'" - " are reserved"); + "'classname', 'name', 'status', 'time', 'type_param', 'value_param'," + " 'file', and 'line' are reserved"); } class UnitTestRecordPropertyTestEnvironment : public Environment { |