#include "base/test/metrics/histogram_variants_reader.h"
#include <map>
#include <optional>
#include <string>
#include "base/base_paths.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libxml/chromium/xml_reader.h"
namespace base {
namespace {
std::optional<HistogramVariantsEntryMap> ParseVariantsFromHistogramsXml(
const std::string& variants_name,
XmlReader& reader) {
HistogramVariantsEntryMap result;
bool success = true;
while (true) {
const std::string node_name = reader.NodeName();
if (node_name == "variants" && reader.IsClosingElement()) {
break;
}
if (node_name == "variant") {
std::string name;
std::string summary;
const bool has_name = reader.NodeAttribute("name", &name);
const bool has_summary = reader.NodeAttribute("summary", &summary);
if (!has_name) {
ADD_FAILURE() << "Bad " << variants_name << " variant entry, summary='"
<< summary << "'): No 'name' attribute.";
success = false;
}
if (!has_summary) {
ADD_FAILURE() << "Bad " << variants_name << " variant entry, name='"
<< name << "'): No 'summary' attribute.";
success = false;
}
if (has_name) {
const auto insert_result = result.emplace(name, summary);
if (!insert_result.second) {
ADD_FAILURE() << "Duplicate entry in " << variants_name
<< " variant entry, name='" << name << ')';
success = false;
}
}
}
reader.Next();
}
return success ? std::make_optional(result) : std::nullopt;
}
}
std::optional<HistogramVariantsEntryMap> ReadVariantsFromHistogramsXml(
const std::string& variants_name,
const std::string& subdirectory,
bool from_metadata) {
base::FilePath src_root;
if (!base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &src_root)) {
ADD_FAILURE() << "Failed to get src root.";
return std::nullopt;
}
base::FilePath path =
src_root.AppendASCII("tools").AppendASCII("metrics").AppendASCII(
"histograms");
if (from_metadata) {
path = path.AppendASCII("metadata");
}
if (!subdirectory.empty()) {
path = path.AppendASCII(subdirectory);
}
path = path.AppendASCII("histograms.xml");
if (!base::PathExists(path)) {
ADD_FAILURE() << "File does not exist: " << path;
return std::nullopt;
}
XmlReader reader;
if (!reader.LoadFile(path.MaybeAsASCII())) {
ADD_FAILURE() << "Failed to load " << path;
return std::nullopt;
}
std::optional<HistogramVariantsEntryMap> result;
while (true) {
const std::string node_name = reader.NodeName();
if (node_name == "variants") {
std::string name;
if (reader.NodeAttribute("name", &name) && name == variants_name) {
if (result.has_value()) {
ADD_FAILURE() << "Duplicate variant '" << variants_name
<< "' found in " << path;
return std::nullopt;
}
const bool got_into_variant = reader.Read();
if (!got_into_variant) {
ADD_FAILURE() << "Bad variant '" << variants_name
<< "' (looks empty) found in " << path;
return std::nullopt;
}
result = ParseVariantsFromHistogramsXml(variants_name, reader);
if (!result.has_value()) {
ADD_FAILURE() << "Bad variant '" << variants_name << "' found in "
<< path << " (format error).";
return std::nullopt;
}
}
}
if (reader.Read()) {
continue;
}
if (reader.Next()) {
continue;
}
while (reader.Depth() && !reader.SkipToElement()) {
}
if (!reader.Depth()) {
break;
}
}
return result;
}
}