diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..35a07add3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +[*.{c,h,cpp,hpp}] +indent_style = space +indent_size = 4 + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..979a9c17a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,24 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Explicitly declare text files +*.md text diff=markdown +*.txt text +*.csv text +*.yml text +*.yaml text +*.json text +*.xml text +*.html text diff=html +*.css text diff=css + +# Denote binary files +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.pdf binary +*.zip binary +*.gz binary +*.tar binary diff --git a/googlemock/test/gmock_leak_test.py b/googlemock/test/gmock_leak_test.py old mode 100755 new mode 100644 diff --git a/googlemock/test/gmock_output_test.py b/googlemock/test/gmock_output_test.py old mode 100755 new mode 100644 diff --git a/googlemock/test/gmock_test_utils.py b/googlemock/test/gmock_test_utils.py old mode 100755 new mode 100644 diff --git a/googletest/samples/sample11_parameterized_fixture.cc b/googletest/samples/sample11_parameterized_fixture.cc new file mode 100644 index 000000000..f2af50f68 --- /dev/null +++ b/googletest/samples/sample11_parameterized_fixture.cc @@ -0,0 +1,327 @@ +// Copyright 2024 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Sample #11 - Advanced parameterized testing with combined type and value +// parameters, custom name generators, and fixture lifecycle demonstration. +// +// This sample demonstrates: +// 1. Type-parameterized tests for generic containers +// 2. Value-parameterized tests with custom name generators +// 3. Fixture lifecycle (SetUp/TearDown ordering) +// 4. Multiple parameter combinations using Combine, Values, Range +// 5. INSTANTIATE_TEST_SUITE_P with various generators + +#include "sample11_parameterized_fixture.h" + +#include +#include +#include +#include + +#include "gtest/gtest.h" + +// --------------------------------------------------------------------------- +// Part 1: Type-parameterized tests for SortedContainer +// --------------------------------------------------------------------------- + +template +class SortedContainerTest : public ::testing::Test { + protected: + void SetUp() override { + // Track lifecycle + setup_called_ = true; + } + + void TearDown() override { + container_.Clear(); + teardown_called_ = true; + } + + SortedContainer container_; + bool setup_called_ = false; + bool teardown_called_ = false; +}; + +using ContainerTypes = ::testing::Types; +TYPED_TEST_SUITE(SortedContainerTest, ContainerTypes); + +// Helper to create a test value for each type +template +T MakeValue(int n); + +template <> +int MakeValue(int n) { + return n * 10; +} +template <> +double MakeValue(int n) { + return n * 1.5; +} +template <> +std::string MakeValue(int n) { + return "item_" + std::to_string(n); +} + +TYPED_TEST(SortedContainerTest, InsertMaintainsSortOrder) { + ASSERT_TRUE(this->setup_called_); + // Insert in reverse order + for (int i = 5; i >= 1; --i) { + this->container_.Insert(MakeValue(i)); + } + EXPECT_EQ(this->container_.Size(), 5u); + // Verify sorted order + auto all = this->container_.GetAll(); + for (size_t i = 1; i < all.size(); ++i) { + EXPECT_LE(all[i - 1], all[i]) << "Elements not sorted at index " << i; + } +} + +TYPED_TEST(SortedContainerTest, ContainsFindsInsertedElements) { + for (int i = 1; i <= 3; ++i) { + this->container_.Insert(MakeValue(i)); + } + for (int i = 1; i <= 3; ++i) { + EXPECT_TRUE(this->container_.Contains(MakeValue(i))); + } + EXPECT_FALSE(this->container_.Contains(MakeValue(99))); +} + +TYPED_TEST(SortedContainerTest, RemoveDeletesElement) { + this->container_.Insert(MakeValue(1)); + this->container_.Insert(MakeValue(2)); + this->container_.Insert(MakeValue(3)); + + EXPECT_TRUE(this->container_.Remove(MakeValue(2))); + EXPECT_EQ(this->container_.Size(), 2u); + EXPECT_FALSE(this->container_.Contains(MakeValue(2))); + EXPECT_TRUE(this->container_.Contains(MakeValue(1))); + EXPECT_TRUE(this->container_.Contains(MakeValue(3))); +} + +TYPED_TEST(SortedContainerTest, EmptyContainerBehavior) { + EXPECT_TRUE(this->container_.Empty()); + EXPECT_EQ(this->container_.Size(), 0u); + EXPECT_FALSE(this->container_.Remove(MakeValue(1))); +} + +// --------------------------------------------------------------------------- +// Part 2: Value-parameterized tests for StatsCalculator +// --------------------------------------------------------------------------- + +struct StatsTestData { + std::string name; + std::vector data; + double expected_mean; + double expected_median; + double tolerance; +}; + +class StatsCalculatorTest : public ::testing::TestWithParam { + protected: + void SetUp() override { calc_ = StatsCalculator(6); } + + void TearDown() override { + // Lifecycle demonstration: TearDown called after each test + } + + StatsCalculator calc_; +}; + +// Custom name generator for readable test names +struct StatsTestNameGenerator { + std::string operator()( + const ::testing::TestParamInfo& info) const { + return info.param.name; + } +}; + +TEST_P(StatsCalculatorTest, MeanCalculation) { + const auto& param = GetParam(); + double result = calc_.Mean(param.data); + EXPECT_NEAR(result, param.expected_mean, param.tolerance) + << "Mean calculation failed for dataset: " << param.name; +} + +TEST_P(StatsCalculatorTest, MedianCalculation) { + const auto& param = GetParam(); + double result = calc_.Median(param.data); + EXPECT_NEAR(result, param.expected_median, param.tolerance) + << "Median calculation failed for dataset: " << param.name; +} + +TEST_P(StatsCalculatorTest, VarianceIsNonNegative) { + const auto& param = GetParam(); + double variance = calc_.Variance(param.data); + EXPECT_GE(variance, 0.0) << "Variance should be non-negative"; +} + +TEST_P(StatsCalculatorTest, StdDevMatchesSqrtVariance) { + const auto& param = GetParam(); + double variance = calc_.Variance(param.data); + double stddev = calc_.StandardDeviation(param.data); + EXPECT_NEAR(stddev, std::sqrt(variance), param.tolerance); +} + +INSTANTIATE_TEST_SUITE_P( + BasicDatasets, StatsCalculatorTest, + ::testing::Values( + StatsTestData{"Uniform", {1.0, 2.0, 3.0, 4.0, 5.0}, 3.0, 3.0, 1e-6}, + StatsTestData{"SingleElement", {42.0}, 42.0, 42.0, 1e-6}, + StatsTestData{"TwoElements", {10.0, 20.0}, 15.0, 15.0, 1e-6}, + StatsTestData{"Negative", {-5.0, -3.0, -1.0, 0.0, 2.0}, -1.4, -1.0, + 1e-6}, + StatsTestData{"LargeValues", {1e6, 2e6, 3e6}, 2e6, 2e6, 1.0}), + StatsTestNameGenerator()); + +// --------------------------------------------------------------------------- +// Part 3: Combined parameter tests with Combine and tuple parameters +// --------------------------------------------------------------------------- + +class CombinedParamTest + : public ::testing::TestWithParam> { + protected: + void SetUp() override { + iterations_ = std::get<0>(GetParam()); + verbose_ = std::get<1>(GetParam()); + mode_ = std::get<2>(GetParam()); + } + + int iterations_; + bool verbose_; + std::string mode_; +}; + +// Custom name generator for combined parameters +struct CombinedTestNameGenerator { + std::string operator()( + const ::testing::TestParamInfo< + std::tuple>& info) const { + std::ostringstream oss; + oss << "Iter" << std::get<0>(info.param) << "_" + << (std::get<1>(info.param) ? "Verbose" : "Quiet") << "_" + << std::get<2>(info.param); + return oss.str(); + } +}; + +TEST_P(CombinedParamTest, IterationsArePositive) { + EXPECT_GT(iterations_, 0) << "Iterations must be positive"; +} + +TEST_P(CombinedParamTest, ModeIsValid) { + EXPECT_TRUE(mode_ == "fast" || mode_ == "balanced" || mode_ == "thorough") + << "Unknown mode: " << mode_; +} + +TEST_P(CombinedParamTest, ParameterCombinationWorks) { + // Verify that each parameter combination produces a valid configuration + TestConfig config(mode_, iterations_, verbose_, 0.001); + EXPECT_EQ(config.iterations, iterations_); + EXPECT_EQ(config.verbose, verbose_); + EXPECT_EQ(config.name, mode_); + EXPECT_DOUBLE_EQ(config.tolerance, 0.001); +} + +INSTANTIATE_TEST_SUITE_P( + AllCombinations, CombinedParamTest, + ::testing::Combine(::testing::Values(1, 5, 10), + ::testing::Bool(), + ::testing::Values("fast", "balanced", "thorough")), + CombinedTestNameGenerator()); + +// --------------------------------------------------------------------------- +// Part 4: Range-based parameterized tests +// --------------------------------------------------------------------------- + +class RangeParamTest : public ::testing::TestWithParam { + protected: + void SetUp() override { + value_ = GetParam(); + container_.Clear(); + } + + void TearDown() override { container_.Clear(); } + + int value_; + SortedContainer container_; +}; + +TEST_P(RangeParamTest, InsertNElementsMaintainsCount) { + for (int i = 0; i < value_; ++i) { + container_.Insert(i * 7); // Non-sequential values + } + EXPECT_EQ(container_.Size(), static_cast(value_)); +} + +TEST_P(RangeParamTest, InsertNElementsMaintainsOrder) { + // Insert in reverse order + for (int i = value_ - 1; i >= 0; --i) { + container_.Insert(i); + } + auto all = container_.GetAll(); + for (int i = 0; i < value_; ++i) { + EXPECT_EQ(all[i], i); + } +} + +struct RangeTestNameGenerator { + std::string operator()(const ::testing::TestParamInfo& info) const { + return "Count_" + std::to_string(info.param); + } +}; + +INSTANTIATE_TEST_SUITE_P(SmallRange, RangeParamTest, + ::testing::Range(1, 8), + RangeTestNameGenerator()); + +INSTANTIATE_TEST_SUITE_P(LargeRange, RangeParamTest, + ::testing::Values(50, 100, 500), + RangeTestNameGenerator()); + +// --------------------------------------------------------------------------- +// Part 5: Fixture lifecycle demonstration +// --------------------------------------------------------------------------- + +class LifecycleTest : public ::testing::Test { + protected: + static void SetUpTestSuite() { suite_setup_count_++; } + + static void TearDownTestSuite() { suite_teardown_count_++; } + + void SetUp() override { instance_setup_count_++; } + + void TearDown() override { instance_teardown_count_++; } + + static int suite_setup_count_; + static int suite_teardown_count_; + static int instance_setup_count_; + static int instance_teardown_count_; +}; + +int LifecycleTest::suite_setup_count_ = 0; +int LifecycleTest::suite_teardown_count_ = 0; +int LifecycleTest::instance_setup_count_ = 0; +int LifecycleTest::instance_teardown_count_ = 0; + +TEST_F(LifecycleTest, SuiteSetUpCalledOnce) { + EXPECT_EQ(suite_setup_count_, 1) + << "SetUpTestSuite should be called exactly once before all tests"; +} + +TEST_F(LifecycleTest, InstanceSetUpCalledPerTest) { + EXPECT_GE(instance_setup_count_, 1) + << "SetUp should be called at least once"; + EXPECT_EQ(instance_setup_count_, instance_teardown_count_ + 1) + << "SetUp count should be one more than TearDown count during a test"; +} diff --git a/googletest/samples/sample11_parameterized_fixture.h b/googletest/samples/sample11_parameterized_fixture.h new file mode 100644 index 000000000..f5e7a28b5 --- /dev/null +++ b/googletest/samples/sample11_parameterized_fixture.h @@ -0,0 +1,127 @@ +// Copyright 2024 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Sample #11 - Advanced parameterized testing with combined type and value +// parameters, custom name generators, and fixture lifecycle demonstration. + +#ifndef GOOGLETEST_SAMPLES_SAMPLE11_PARAMETERIZED_FIXTURE_H_ +#define GOOGLETEST_SAMPLES_SAMPLE11_PARAMETERIZED_FIXTURE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +// A simple container that supports different storage strategies. +// This is the class under test for our type-parameterized tests. +template +class SortedContainer { + public: + void Insert(const T& value) { + auto it = std::lower_bound(data_.begin(), data_.end(), value); + data_.insert(it, value); + } + + bool Contains(const T& value) const { + return std::binary_search(data_.begin(), data_.end(), value); + } + + size_t Size() const { return data_.size(); } + + bool Empty() const { return data_.empty(); } + + const T& At(size_t index) const { return data_.at(index); } + + void Clear() { data_.clear(); } + + // Returns elements in sorted order + std::vector GetAll() const { return data_; } + + // Remove first occurrence of value + bool Remove(const T& value) { + auto it = std::lower_bound(data_.begin(), data_.end(), value); + if (it != data_.end() && *it == value) { + data_.erase(it); + return true; + } + return false; + } + + private: + std::vector data_; +}; + +// A numeric statistics calculator for value-parameterized tests +class StatsCalculator { + public: + explicit StatsCalculator(int precision = 6) : precision_(precision) {} + + double Mean(const std::vector& data) const { + if (data.empty()) return 0.0; + double sum = std::accumulate(data.begin(), data.end(), 0.0); + return RoundToPrecision(sum / static_cast(data.size())); + } + + double Variance(const std::vector& data) const { + if (data.size() < 2) return 0.0; + double m = Mean(data); + double sumSq = 0.0; + for (const auto& v : data) { + double diff = v - m; + sumSq += diff * diff; + } + return RoundToPrecision(sumSq / static_cast(data.size() - 1)); + } + + double StandardDeviation(const std::vector& data) const { + return RoundToPrecision(std::sqrt(Variance(data))); + } + + double Median(std::vector data) const { + if (data.empty()) return 0.0; + std::sort(data.begin(), data.end()); + size_t mid = data.size() / 2; + if (data.size() % 2 == 0) { + return RoundToPrecision((data[mid - 1] + data[mid]) / 2.0); + } + return data[mid]; + } + + int GetPrecision() const { return precision_; } + + private: + double RoundToPrecision(double value) const { + double factor = std::pow(10.0, precision_); + return std::round(value * factor) / factor; + } + + int precision_; +}; + +// Configuration struct for parameterized tests +struct TestConfig { + std::string name; + int iterations; + bool verbose; + double tolerance; + + TestConfig(const std::string& n, int iter, bool v, double tol) + : name(n), iterations(iter), verbose(v), tolerance(tol) {} +}; + +#endif // GOOGLETEST_SAMPLES_SAMPLE11_PARAMETERIZED_FIXTURE_H_ diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc index d34a693e4..229688502 100644 --- a/googletest/src/gtest-port.cc +++ b/googletest/src/gtest-port.cc @@ -1258,7 +1258,11 @@ std::string GetCapturedStderr() { size_t GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); - return static_cast(ftell(file)); + const long size = ftell(file); + if (size < 0) { + return 0; + } + return static_cast(size); } std::string ReadEntireFile(FILE* file) { diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index ac90786a0..72f25b5fd 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -3895,7 +3895,9 @@ TestEventRepeater::~TestEventRepeater() { } void TestEventRepeater::Append(TestEventListener* listener) { - listeners_.push_back(listener); + if (listener != nullptr) { + listeners_.push_back(listener); + } } TestEventListener* TestEventRepeater::Release(TestEventListener* listener) { diff --git a/googletest/test/googletest-break-on-failure-unittest.py b/googletest/test/googletest-break-on-failure-unittest.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-catch-exceptions-test.py b/googletest/test/googletest-catch-exceptions-test.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-color-test.py b/googletest/test/googletest-color-test.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-env-var-test.py b/googletest/test/googletest-env-var-test.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-fail-if-no-test-linked-test.py b/googletest/test/googletest-fail-if-no-test-linked-test.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-failfast-unittest.py b/googletest/test/googletest-failfast-unittest.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-filter-unittest.py b/googletest/test/googletest-filter-unittest.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-list-tests-unittest.py b/googletest/test/googletest-list-tests-unittest.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-output-test.py b/googletest/test/googletest-output-test.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-setuptestsuite-test.py b/googletest/test/googletest-setuptestsuite-test.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-shuffle-test.py b/googletest/test/googletest-shuffle-test.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-throw-on-failure-test.py b/googletest/test/googletest-throw-on-failure-test.py old mode 100755 new mode 100644 diff --git a/googletest/test/googletest-uninitialized-test.py b/googletest/test/googletest-uninitialized-test.py old mode 100755 new mode 100644 diff --git a/googletest/test/gtest_help_test.py b/googletest/test/gtest_help_test.py old mode 100755 new mode 100644 diff --git a/googletest/test/gtest_skip_check_output_test.py b/googletest/test/gtest_skip_check_output_test.py old mode 100755 new mode 100644 diff --git a/googletest/test/gtest_skip_environment_check_output_test.py b/googletest/test/gtest_skip_environment_check_output_test.py old mode 100755 new mode 100644 diff --git a/googletest/test/gtest_test_utils.py b/googletest/test/gtest_test_utils.py old mode 100755 new mode 100644 diff --git a/googletest/test/gtest_testbridge_test.py b/googletest/test/gtest_testbridge_test.py old mode 100755 new mode 100644 diff --git a/googletest/test/gtest_xml_outfiles_test.py b/googletest/test/gtest_xml_outfiles_test.py old mode 100755 new mode 100644 diff --git a/googletest/test/gtest_xml_output_unittest.py b/googletest/test/gtest_xml_output_unittest.py old mode 100755 new mode 100644 diff --git a/googletest/test/gtest_xml_test_utils.py b/googletest/test/gtest_xml_test_utils.py old mode 100755 new mode 100644