| // Protocol Buffers - Google's data interchange format | |
| // Copyright 2023 Google Inc. All rights reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file or at | |
| // https://developers.google.com/open-source/licenses/bsd | |
| // | |
| #include <cstdlib> | |
| #include <string> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include "google/protobuf/port.h" | |
| // Must be included last. | |
| #include "google/protobuf/port_def.inc" | |
| namespace { | |
| using testing::AllOf; | |
| using testing::ExitedWithCode; | |
| using testing::HasSubstr; | |
| using testing::Not; | |
| auto MatchOutput(bool expect_output) { | |
| const auto header = HasSubstr("Protobuf debug counters:"); | |
| const auto all = AllOf(header, // | |
| HasSubstr("Foo :"), | |
| HasSubstr(" Bar : 1 (33.33%)"), | |
| HasSubstr(" Baz : 2 (66.67%)"), | |
| HasSubstr(" Total : 3"), // | |
| HasSubstr("Num :"), | |
| HasSubstr(" 32 : 3 (75.00%)"), | |
| HasSubstr(" 128 : 1 (25.00%)"), | |
| HasSubstr(" Total : 4")); | |
| return expect_output ? testing::Matcher<const std::string&>(all) | |
| : testing::Matcher<const std::string&>(Not(header)); | |
| } | |
| #ifdef GTEST_HAS_DEATH_TEST | |
| TEST(DebugCounterTest, RealProvidesReportAtExit) { | |
| EXPECT_EXIT( | |
| { | |
| static google::protobuf::internal::RealDebugCounter counter1("Foo.Bar"); | |
| static google::protobuf::internal::RealDebugCounter counter2("Foo.Baz"); | |
| static google::protobuf::internal::RealDebugCounter counter3("Num.32"); | |
| static google::protobuf::internal::RealDebugCounter counter4("Num.128"); | |
| counter1.Inc(); | |
| counter2.Inc(); | |
| counter2.Inc(); | |
| counter3.Inc(); | |
| counter3.Inc(); | |
| counter3.Inc(); | |
| counter4.Inc(); | |
| exit(0); | |
| }, | |
| ExitedWithCode(0), MatchOutput(true)); | |
| } | |
| TEST(DebugCounterTest, NoopDoesNotProvidesReportAtExit) { | |
| EXPECT_EXIT( | |
| { | |
| static google::protobuf::internal::NoopDebugCounter counter1; | |
| static google::protobuf::internal::NoopDebugCounter counter2; | |
| counter1.Inc(); | |
| counter2.Inc(); | |
| counter2.Inc(); | |
| exit(0); | |
| }, | |
| ExitedWithCode(0), MatchOutput(false)); | |
| // and test that the operations have no side effects. | |
| static_assert((google::protobuf::internal::NoopDebugCounter().Inc(), true), ""); | |
| } | |
| TEST(DebugCounterTest, MacroProvidesReportAtExitDependingOnBuild) { | |
| #if defined(PROTOBUF_INTERNAL_ENABLE_DEBUG_COUNTERS) | |
| constexpr bool match_output = true; | |
| #else | |
| constexpr bool match_output = false; | |
| // and test that the operations have no side effects. | |
| static_assert((PROTOBUF_DEBUG_COUNTER("Foo.Bar").Inc(), true), ""); | |
| #endif | |
| EXPECT_EXIT( | |
| { | |
| PROTOBUF_DEBUG_COUNTER("Foo.Bar").Inc(); | |
| for (int i = 0; i < 2; ++i) { | |
| PROTOBUF_DEBUG_COUNTER("Foo.Baz").Inc(); | |
| } | |
| for (int i = 0; i < 3; ++i) { | |
| PROTOBUF_DEBUG_COUNTER("Num.32").Inc(); | |
| } | |
| PROTOBUF_DEBUG_COUNTER("Num.128").Inc(); | |
| exit(0); | |
| }, | |
| ExitedWithCode(0), MatchOutput(match_output)); | |
| } | |
| #endif // GTEST_HAS_DEATH_TEST | |
| template <typename T> | |
| void CounterOnATemplate() { | |
| static google::protobuf::internal::RealDebugCounter counter("Foo.Bar"); | |
| counter.Inc(); | |
| } | |
| // Regression test for counters on templates. | |
| // It used to be that duplicate names would clobber each other so the total for | |
| // the counter would only take one instantiation into account and undercount. | |
| TEST(DebugCounterTest, DuplicateNamesWorkTogether) { | |
| EXPECT_EXIT( | |
| { | |
| static google::protobuf::internal::RealDebugCounter counter("Foo.Baz"); | |
| CounterOnATemplate<int>(); | |
| CounterOnATemplate<int>(); | |
| CounterOnATemplate<double>(); | |
| counter.Inc(); | |
| counter.Inc(); | |
| exit(0); | |
| }, | |
| ExitedWithCode(0), | |
| AllOf(HasSubstr(" Bar : 3 (60.00%)"), | |
| HasSubstr(" Baz : 2 (40.00%)"), | |
| HasSubstr(" Total : 5"))); | |
| } | |
| TEST(DebugCounterTest, Histograms) { | |
| EXPECT_EXIT( | |
| { | |
| static google::protobuf::internal::RealDebugCounter normal_counter( | |
| "Normal.Counter"); | |
| static google::protobuf::internal::RealDebugCounter log_counter("Log.Counter"); | |
| static google::protobuf::internal::RealDebugCounter linear_counter( | |
| "Linear.Counter"); | |
| normal_counter.Inc(); | |
| normal_counter.Inc(); | |
| normal_counter.Inc(); | |
| for (int i = 0; i < 100; ++i) { | |
| log_counter.IncLog(i); | |
| } | |
| linear_counter.IncBucket(3); | |
| linear_counter.IncBucket(3); | |
| linear_counter.IncBucket(4); | |
| linear_counter.IncBucket(7); | |
| linear_counter.IncBucket(7); | |
| linear_counter.IncBucket(7); | |
| exit(0); | |
| }, | |
| ExitedWithCode(0), | |
| HasSubstr( | |
| R"( | |
| ---Histograms--- | |
| Linear.Counter: | |
| [ 3]:▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▎ | |
| [ 4]:▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▋ | |
| [ 5]: | |
| [ 6]: | |
| [ 7]:▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ | |
| Log.Counter: | |
| [ 0]:▉ | |
| [ 1]:▉ | |
| [ 2]:▉▉ | |
| [ 3]:▉▉▉▉ | |
| [ 4]:▉▉▉▉▉▉▉▉ | |
| [ 5]:▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ | |
| [ 6]:▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ | |
| [ 7]:▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ | |
| )")); | |
| } | |
| } // namespace | |
| #include "google/protobuf/port_undef.inc" |