diff --git a/googlemock/CMakeLists.txt b/googlemock/CMakeLists.txt index 99b2411f3..8bda3181b 100644 --- a/googlemock/CMakeLists.txt +++ b/googlemock/CMakeLists.txt @@ -153,6 +153,7 @@ if (gmock_build_tests) cxx_test(gmock-spec-builders_test gmock_main) cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc) cxx_test(gmock_test gmock_main) + cxx_test(gmock_env_test gmock_main) if (DEFINED GTEST_HAS_PTHREAD) cxx_test(gmock_stress_test gmock) diff --git a/googlemock/include/gmock/internal/gmock-port.h b/googlemock/include/gmock/internal/gmock-port.h index 42d36d2f1..b38912c1b 100644 --- a/googlemock/include/gmock/internal/gmock-port.h +++ b/googlemock/include/gmock/internal/gmock-port.h @@ -57,6 +57,23 @@ #include "gmock/internal/custom/gmock-port.h" #include "gtest/internal/gtest-port.h" +namespace testing { +namespace internal { + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GMOCK_FOO". +GTEST_API_ std::string FlagToEnvVar(const char* flag); + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +GTEST_API_ const char* StringFromGMockEnv( + const char* flag, + const char* default_value); + +} // namespace internal +} // namespace testing + #if defined(GTEST_HAS_ABSL) && !defined(GTEST_NO_ABSL_FLAGS) #include "absl/flags/declare.h" #include "absl/flags/flag.h" @@ -68,6 +85,9 @@ #error "At least Visual C++ 2015 (14.0) is required to compile Google Mock." #endif +// Defines the flag prefixes for Google Mock. +#define GMOCK_FLAG_PREFIX_ "gmock_" + // Macro for referencing flags. This is public as we want the user to // use this syntax to reference Google Mock flags. #define GMOCK_FLAG_NAME_(name) gmock_##name diff --git a/googlemock/src/gmock.cc b/googlemock/src/gmock.cc index b5e714da7..051b8a22d 100644 --- a/googlemock/src/gmock.cc +++ b/googlemock/src/gmock.cc @@ -33,11 +33,40 @@ #include "gmock/internal/gmock-port.h" +namespace testing { +namespace internal { + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GMOCK_FOO". +std::string FlagToEnvVar(const char* flag) { + const std::string full_flag = std::string(GMOCK_FLAG_PREFIX_) + flag; + + std::string env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var += toupper(full_flag.c_str()[i]); + } + + return env_var; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGMockEnv(const char* flag, const char* default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == nullptr ? default_value : value; +} + +} // namespace internal +} // namespace testing + GMOCK_DEFINE_bool_(catch_leaked_mocks, true, "true if and only if Google Mock should report leaked " "mock objects as failures."); -GMOCK_DEFINE_string_(verbose, testing::internal::kWarningVerbosity, +GMOCK_DEFINE_string_(verbose, testing::internal::StringFromGMockEnv("verbose", + testing::internal::kWarningVerbosity), "Controls how verbose Google Mock's output is." " Valid values:\n" " info - prints all messages.\n" diff --git a/googlemock/test/BUILD.bazel b/googlemock/test/BUILD.bazel index d4297c80f..1d119b322 100644 --- a/googlemock/test/BUILD.bazel +++ b/googlemock/test/BUILD.bazel @@ -116,3 +116,10 @@ cc_test( srcs = ["gmock_test.cc"], deps = ["//:gtest_main"], ) + +cc_test( + name = "gmock_env_test", + size = "small", + srcs = ["gmock_env_test.cc"], + deps = ["//:gtest_main"], +) diff --git a/googlemock/test/gmock_env_test.cc b/googlemock/test/gmock_env_test.cc new file mode 100644 index 000000000..770518559 --- /dev/null +++ b/googlemock/test/gmock_env_test.cc @@ -0,0 +1,142 @@ +// Copyright 2025, 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. + +// Tests for the StringFromGMockEnv() function that enables setting +// verbosity level from the GMOCK_VERBOSE environment variable. + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +// The StringFromGMockEnv() function is declared in gmock-port.h and implemented +// in gmock.cc. We test it indirectly through the GMOCK_FLAG(verbose) which is +// initialized with this function. + +namespace { + +// Function to set environment variable for testing +void SetEnv(const char* name, const char* value) { +#ifdef _WIN32 + _putenv_s(name, value); +#else + setenv(name, value, 1); +#endif +} + +// Function to unset environment variable for testing +void UnsetEnv(const char* name) { +#ifdef _WIN32 + _putenv_s(name, ""); +#else + unsetenv(name); +#endif +} + +// Test fixture for environment variable tests +class GMockVerbosityEnvTest : public ::testing::Test { + protected: + void SetUp() override { + // Save the original verbose flag value + original_verbose_ = GMOCK_FLAG_GET(verbose); + + // Unset the GMOCK_VERBOSE environment variable to start with a clean state + UnsetEnv("GMOCK_VERBOSE"); + } + + void TearDown() override { + // Restore the original verbose flag value + GMOCK_FLAG_SET(verbose, original_verbose_); + + // Clean up the environment variable + UnsetEnv("GMOCK_VERBOSE"); + } + + std::string original_verbose_; +}; + +// Tests that when GMOCK_VERBOSE is not set, the default value is used +TEST_F(GMockVerbosityEnvTest, DefaultValueWhenEnvNotSet) { + // Re-initialize Google Mock to pick up the environment variable + // This will call InitGoogleMock which will use StringFromGMockEnv() + int argc = 1; + const char* argv[] = {"test_program"}; + testing::InitGoogleMock(&argc, const_cast(argv)); + + // The default value should be "warning" + EXPECT_EQ(GMOCK_FLAG_GET(verbose), "warning"); +} + +// Tests that when GMOCK_VERBOSE is set to "info", that value is used +TEST_F(GMockVerbosityEnvTest, InfoValueWhenEnvSet) { + // Set the environment variable + SetEnv("GMOCK_VERBOSE", "info"); + + // Re-initialize Google Mock to pick up the environment variable + int argc = 1; + const char* argv[] = {"test_program"}; + testing::InitGoogleMock(&argc, const_cast(argv)); + + // The value should be "info" as set in the environment + EXPECT_EQ(GMOCK_FLAG_GET(verbose), "info"); +} + +// Tests that when GMOCK_VERBOSE is set to "error", that value is used +TEST_F(GMockVerbosityEnvTest, ErrorValueWhenEnvSet) { + // Set the environment variable + SetEnv("GMOCK_VERBOSE", "error"); + + // Re-initialize Google Mock to pick up the environment variable + int argc = 1; + const char* argv[] = {"test_program"}; + testing::InitGoogleMock(&argc, const_cast(argv)); + + // The value should be "error" as set in the environment + EXPECT_EQ(GMOCK_FLAG_GET(verbose), "error"); +} + +// Tests that command line flags take precedence over environment variables +TEST_F(GMockVerbosityEnvTest, CommandLineFlagOverridesEnv) { + // Set the environment variable + SetEnv("GMOCK_VERBOSE", "info"); + + // Set up command line arguments with the --gmock_verbose flag + int argc = 2; + const char* argv[] = {"test_program", "--gmock_verbose=error"}; + testing::InitGoogleMock(&argc, const_cast(argv)); + + // The value should be "error" from the command line, not "info" from the + // environment + EXPECT_EQ(GMOCK_FLAG_GET(verbose), "error"); +} + +} // namespace + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file