1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/test/test_proto_loader.h"
6
7 #include "base/files/file_util.h"
8 #include "base/notreached.h"
9 #include "base/path_service.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "third_party/protobuf/src/google/protobuf/message.h"
13 #include "third_party/protobuf/src/google/protobuf/text_format.h"
14
15 namespace base {
16
TestProtoLoader(const base::FilePath & descriptor_path,base::StringPiece type_name)17 TestProtoLoader::TestProtoLoader(const base::FilePath& descriptor_path,
18 base::StringPiece type_name) {
19 // Load the descriptors and find the one for |type_name|.
20 std::string package, name;
21 std::vector<std::string> type_name_parts = base::SplitString(
22 type_name, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
23 DCHECK_GE(type_name_parts.size(), 2U) << "|type_name| should include package";
24
25 prototype_ = GetPrototype(
26 descriptor_path, /*package =*/
27 base::JoinString(
28 base::make_span(type_name_parts.begin(), type_name_parts.size() - 1),
29 "."),
30 /* name = */ type_name_parts.back());
31 DCHECK_NE(nullptr, prototype_);
32 }
33
34 TestProtoLoader::~TestProtoLoader() = default;
35
GetPrototype(base::FilePath descriptor_path,base::StringPiece package,base::StringPiece name)36 const google::protobuf::Message* TestProtoLoader::GetPrototype(
37 base::FilePath descriptor_path,
38 base::StringPiece package,
39 base::StringPiece name) {
40 std::string file_contents;
41
42 if (!base::ReadFileToString(descriptor_path, &file_contents)) {
43 NOTREACHED() << "Couldn't load contents of " << descriptor_path;
44 return nullptr;
45 }
46
47 if (!descriptor_set_.ParseFromString(file_contents)) {
48 NOTREACHED() << "Couldn't parse descriptor from " << descriptor_path;
49 return nullptr;
50 }
51
52 for (int file_i = 0; file_i < descriptor_set_.file_size(); ++file_i) {
53 const google::protobuf::FileDescriptorProto& file =
54 descriptor_set_.file(file_i);
55 if (file.package() != package) {
56 continue;
57 }
58 const google::protobuf::FileDescriptor* descriptor =
59 descriptor_pool_.BuildFile(file);
60 for (int message_type_i = 0;
61 message_type_i < descriptor->message_type_count(); ++message_type_i) {
62 const google::protobuf::Descriptor* message_type =
63 descriptor->message_type(message_type_i);
64 if (message_type->name() != name) {
65 continue;
66 }
67 return dynamic_message_factory_.GetPrototype(message_type);
68 }
69 }
70 NOTREACHED() << "Couldn't find " << package << "." << name << "in "
71 << descriptor_path;
72 return nullptr;
73 }
74
ParseFromText(const std::string & proto_text,std::string & serialized_message)75 void TestProtoLoader::ParseFromText(const std::string& proto_text,
76 std::string& serialized_message) {
77 // Parse the text using the descriptor-generated message and send it to
78 // |destination|.
79 std::unique_ptr<google::protobuf::Message> message(prototype_->New());
80 bool success =
81 google::protobuf::TextFormat::ParseFromString(proto_text, message.get());
82 success |= message->SerializeToString(&serialized_message);
83 DCHECK(success);
84 }
85
PrintToText(const std::string & serialized_message,std::string & proto_text)86 void TestProtoLoader::PrintToText(const std::string& serialized_message,
87 std::string& proto_text) {
88 // Parse the text using the descriptor-generated message and send it to
89 // |destination|.
90 std::unique_ptr<google::protobuf::Message> message(prototype_->New());
91 bool success = message->ParseFromString(serialized_message);
92 success |= google::protobuf::TextFormat::PrintToString(*message, &proto_text);
93 DCHECK(success);
94 }
95
96 } // namespace base
97