|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/test/histogram_tester.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include "base/metrics/histogram.h" | 
|  | #include "base/metrics/histogram_samples.h" | 
|  | #include "base/metrics/metrics_hashes.h" | 
|  | #include "base/metrics/sample_map.h" | 
|  | #include "base/metrics/statistics_recorder.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | HistogramTester::HistogramTester() { | 
|  | // Record any histogram data that exists when the object is created so it can | 
|  | // be subtracted later. | 
|  | for (const auto* const histogram : StatisticsRecorder::GetHistograms()) { | 
|  | histograms_snapshot_[histogram->histogram_name()] = | 
|  | histogram->SnapshotSamples(); | 
|  | } | 
|  | } | 
|  |  | 
|  | HistogramTester::~HistogramTester() = default; | 
|  |  | 
|  | void HistogramTester::ExpectUniqueSample( | 
|  | const std::string& name, | 
|  | HistogramBase::Sample sample, | 
|  | HistogramBase::Count expected_count) const { | 
|  | HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 
|  | EXPECT_NE(nullptr, histogram) << "Histogram \"" << name | 
|  | << "\" does not exist."; | 
|  |  | 
|  | if (histogram) { | 
|  | std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); | 
|  | CheckBucketCount(name, sample, expected_count, *samples); | 
|  | CheckTotalCount(name, expected_count, *samples); | 
|  | } | 
|  | } | 
|  |  | 
|  | void HistogramTester::ExpectBucketCount( | 
|  | const std::string& name, | 
|  | HistogramBase::Sample sample, | 
|  | HistogramBase::Count expected_count) const { | 
|  | HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 
|  | EXPECT_NE(nullptr, histogram) << "Histogram \"" << name | 
|  | << "\" does not exist."; | 
|  |  | 
|  | if (histogram) { | 
|  | std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); | 
|  | CheckBucketCount(name, sample, expected_count, *samples); | 
|  | } | 
|  | } | 
|  |  | 
|  | void HistogramTester::ExpectTotalCount(const std::string& name, | 
|  | HistogramBase::Count count) const { | 
|  | HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 
|  | if (histogram) { | 
|  | std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); | 
|  | CheckTotalCount(name, count, *samples); | 
|  | } else { | 
|  | // No histogram means there were zero samples. | 
|  | EXPECT_EQ(count, 0) << "Histogram \"" << name << "\" does not exist."; | 
|  | } | 
|  | } | 
|  |  | 
|  | void HistogramTester::ExpectTimeBucketCount(const std::string& name, | 
|  | TimeDelta sample, | 
|  | HistogramBase::Count count) const { | 
|  | ExpectBucketCount(name, sample.InMilliseconds(), count); | 
|  | } | 
|  |  | 
|  | std::vector<Bucket> HistogramTester::GetAllSamples( | 
|  | const std::string& name) const { | 
|  | std::vector<Bucket> samples; | 
|  | std::unique_ptr<HistogramSamples> snapshot = | 
|  | GetHistogramSamplesSinceCreation(name); | 
|  | if (snapshot) { | 
|  | for (auto it = snapshot->Iterator(); !it->Done(); it->Next()) { | 
|  | HistogramBase::Sample sample; | 
|  | HistogramBase::Count count; | 
|  | it->Get(&sample, nullptr, &count); | 
|  | samples.push_back(Bucket(sample, count)); | 
|  | } | 
|  | } | 
|  | return samples; | 
|  | } | 
|  |  | 
|  | HistogramBase::Count HistogramTester::GetBucketCount( | 
|  | const std::string& name, | 
|  | HistogramBase::Sample sample) const { | 
|  | HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 
|  | EXPECT_NE(nullptr, histogram) | 
|  | << "Histogram \"" << name << "\" does not exist."; | 
|  | HistogramBase::Count count = 0; | 
|  | if (histogram) { | 
|  | std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples(); | 
|  | GetBucketCountForSamples(name, sample, *samples, &count); | 
|  | } | 
|  | return count; | 
|  | } | 
|  |  | 
|  | void HistogramTester::GetBucketCountForSamples( | 
|  | const std::string& name, | 
|  | HistogramBase::Sample sample, | 
|  | const HistogramSamples& samples, | 
|  | HistogramBase::Count* count) const { | 
|  | *count = samples.GetCount(sample); | 
|  | auto histogram_data = histograms_snapshot_.find(name); | 
|  | if (histogram_data != histograms_snapshot_.end()) | 
|  | *count -= histogram_data->second->GetCount(sample); | 
|  | } | 
|  |  | 
|  | HistogramTester::CountsMap HistogramTester::GetTotalCountsForPrefix( | 
|  | const std::string& prefix) const { | 
|  | EXPECT_TRUE(prefix.find('.') != std::string::npos) | 
|  | << "|prefix| ought to contain at least one period, to avoid matching too" | 
|  | << " many histograms."; | 
|  |  | 
|  | CountsMap result; | 
|  |  | 
|  | // Find candidate matches by using the logic built into GetSnapshot(). | 
|  | for (const HistogramBase* histogram : StatisticsRecorder::GetHistograms()) { | 
|  | if (!StartsWith(histogram->histogram_name(), prefix, | 
|  | CompareCase::SENSITIVE)) { | 
|  | continue; | 
|  | } | 
|  | std::unique_ptr<HistogramSamples> new_samples = | 
|  | GetHistogramSamplesSinceCreation(histogram->histogram_name()); | 
|  | // Omit unchanged histograms from the result. | 
|  | if (new_samples->TotalCount()) { | 
|  | result[histogram->histogram_name()] = new_samples->TotalCount(); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<HistogramSamples> | 
|  | HistogramTester::GetHistogramSamplesSinceCreation( | 
|  | const std::string& histogram_name) const { | 
|  | HistogramBase* histogram = StatisticsRecorder::FindHistogram(histogram_name); | 
|  | // Whether the histogram exists or not may not depend on the current test | 
|  | // calling this method, but rather on which tests ran before and possibly | 
|  | // generated a histogram or not (see http://crbug.com/473689). To provide a | 
|  | // response which is independent of the previously run tests, this method | 
|  | // creates empty samples in the absence of the histogram, rather than | 
|  | // returning null. | 
|  | if (!histogram) { | 
|  | return std::unique_ptr<HistogramSamples>( | 
|  | new SampleMap(HashMetricName(histogram_name))); | 
|  | } | 
|  | std::unique_ptr<HistogramSamples> named_samples = | 
|  | histogram->SnapshotSamples(); | 
|  | auto original_samples_it = histograms_snapshot_.find(histogram_name); | 
|  | if (original_samples_it != histograms_snapshot_.end()) | 
|  | named_samples->Subtract(*original_samples_it->second.get()); | 
|  | return named_samples; | 
|  | } | 
|  |  | 
|  | void HistogramTester::CheckBucketCount(const std::string& name, | 
|  | HistogramBase::Sample sample, | 
|  | HistogramBase::Count expected_count, | 
|  | const HistogramSamples& samples) const { | 
|  | int actual_count; | 
|  | GetBucketCountForSamples(name, sample, samples, &actual_count); | 
|  |  | 
|  | EXPECT_EQ(expected_count, actual_count) | 
|  | << "Histogram \"" << name | 
|  | << "\" does not have the right number of samples (" << expected_count | 
|  | << ") in the expected bucket (" << sample << "). It has (" << actual_count | 
|  | << ")."; | 
|  | } | 
|  |  | 
|  | void HistogramTester::CheckTotalCount(const std::string& name, | 
|  | HistogramBase::Count expected_count, | 
|  | const HistogramSamples& samples) const { | 
|  | int actual_count = samples.TotalCount(); | 
|  | auto histogram_data = histograms_snapshot_.find(name); | 
|  | if (histogram_data != histograms_snapshot_.end()) | 
|  | actual_count -= histogram_data->second->TotalCount(); | 
|  |  | 
|  | EXPECT_EQ(expected_count, actual_count) | 
|  | << "Histogram \"" << name | 
|  | << "\" does not have the right total number of samples (" | 
|  | << expected_count << "). It has (" << actual_count << ")."; | 
|  | } | 
|  |  | 
|  | bool Bucket::operator==(const Bucket& other) const { | 
|  | return min == other.min && count == other.count; | 
|  | } | 
|  |  | 
|  | void PrintTo(const Bucket& bucket, std::ostream* os) { | 
|  | *os << "Bucket " << bucket.min << ": " << bucket.count; | 
|  | } | 
|  |  | 
|  | }  // namespace base |