1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 // This test insures that
9 // csharp/src/Google.Protobuf/Reflection/Descriptor.cs match exactly
10 // what would be generated by the protocol compiler. The file is not
11 // generated automatically at build time.
12 //
13 // If this test fails, run the script
14 // "generate_descriptor_proto.sh" and add the changed files under
15 // csharp/src/ to your changelist.
16
17 #include "google/protobuf/testing/file.h"
18 #include "google/protobuf/testing/googletest.h"
19 #include <gtest/gtest.h>
20 #include "absl/container/flat_hash_map.h"
21 #include "absl/strings/ascii.h"
22 #include "absl/strings/escaping.h"
23 #include "absl/strings/str_replace.h"
24 #include "absl/strings/str_split.h"
25 #include "absl/strings/substitute.h"
26 #include "google/protobuf/compiler/csharp/csharp_generator.h"
27 #include "google/protobuf/compiler/importer.h"
28 #include "google/protobuf/descriptor.h"
29 #include "google/protobuf/io/zero_copy_stream_impl.h"
30
31 namespace google {
32 namespace protobuf {
33 namespace compiler {
34 namespace csharp {
35
36 namespace {
37
38 class MockErrorCollector : public MultiFileErrorCollector {
39 public:
MockErrorCollector()40 MockErrorCollector() {}
~MockErrorCollector()41 ~MockErrorCollector() {}
42
43 std::string text_;
44
45 // implements ErrorCollector ---------------------------------------
RecordError(absl::string_view filename,int line,int column,absl::string_view message)46 void RecordError(absl::string_view filename, int line, int column,
47 absl::string_view message) {
48 absl::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column,
49 message);
50 }
51 };
52
53 class MockGeneratorContext : public GeneratorContext {
54 public:
ExpectFileMatches(const std::string & virtual_filename,const std::string & physical_filename)55 void ExpectFileMatches(const std::string& virtual_filename,
56 const std::string& physical_filename) {
57 auto it = files_.find(virtual_filename);
58 ASSERT_TRUE(it != files_.end())
59 << "Generator failed to generate file: " << virtual_filename;
60 std::string expected_contents = *it->second;
61
62 std::string actual_contents;
63 ABSL_CHECK_OK(File::GetContentsAsText(
64 absl::StrCat(TestSourceDir(), "/", physical_filename), &actual_contents,
65 true))
66 << "Unable to get " << physical_filename;
67 EXPECT_TRUE(actual_contents == expected_contents)
68 << physical_filename << " needs to be regenerated. Please run "
69 "generate_descriptor_proto.sh. Then add this file "
70 "to your CL.";
71 }
72
73 // implements GeneratorContext --------------------------------------
74
Open(const std::string & filename)75 virtual io::ZeroCopyOutputStream* Open(const std::string& filename) {
76 auto& map_slot = files_[filename];
77 map_slot.reset(new std::string);
78 return new io::StringOutputStream(map_slot.get());
79 }
80
81 private:
82 absl::flat_hash_map<std::string, std::unique_ptr<std::string>> files_;
83 };
84
85 class GenerateAndTest {
86 public:
GenerateAndTest()87 GenerateAndTest() {}
Run(const FileDescriptor * proto_file,std::string file1,std::string file2)88 void Run(const FileDescriptor* proto_file, std::string file1,
89 std::string file2) {
90 ASSERT_TRUE(proto_file != nullptr) << TestSourceDir();
91 ASSERT_TRUE(generator_.Generate(proto_file, parameter_,
92 &context_, &error_));
93 context_.ExpectFileMatches(file1, file2);
94 }
SetParameter(std::string parameter)95 void SetParameter(std::string parameter) {
96 parameter_ = parameter;
97 }
98
99 private:
100 Generator generator_;
101 MockGeneratorContext context_;
102 std::string error_;
103 std::string parameter_;
104 };
105
TEST(CsharpBootstrapTest,GeneratedCsharpDescriptorMatches)106 TEST(CsharpBootstrapTest, GeneratedCsharpDescriptorMatches) {
107 // Skip this whole test if the csharp directory doesn't exist (i.e., a C++11
108 // only distribution).
109 std::string descriptor_file_name =
110 "../csharp/src/Google.Protobuf/Reflection/Descriptor.cs";
111 if (!File::Exists(absl::StrCat(TestSourceDir(), "/", descriptor_file_name))) {
112 return;
113 }
114
115 MockErrorCollector error_collector;
116 DiskSourceTree source_tree;
117 Importer importer(&source_tree, &error_collector);
118 GenerateAndTest generate_test;
119
120 generate_test.SetParameter("base_namespace=Google.Protobuf");
121 source_tree.MapPath("", TestSourceDir());
122 generate_test.Run(importer.Import("google/protobuf/descriptor.proto"),
123 "Reflection/Descriptor.cs",
124 "../csharp/src/Google.Protobuf/Reflection/Descriptor.cs");
125 generate_test.Run(importer.Import("google/protobuf/any.proto"),
126 "WellKnownTypes/Any.cs",
127 "../csharp/src/Google.Protobuf/WellKnownTypes/Any.cs");
128 generate_test.Run(importer.Import("google/protobuf/api.proto"),
129 "WellKnownTypes/Api.cs",
130 "../csharp/src/Google.Protobuf/WellKnownTypes/Api.cs");
131 generate_test.Run(importer.Import("google/protobuf/duration.proto"),
132 "WellKnownTypes/Duration.cs",
133 "../csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs");
134 generate_test.Run(importer.Import("google/protobuf/empty.proto"),
135 "WellKnownTypes/Empty.cs",
136 "../csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs");
137 generate_test.Run(importer.Import("google/protobuf/field_mask.proto"),
138 "WellKnownTypes/FieldMask.cs",
139 "../csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs");
140 generate_test.Run(importer.Import("google/protobuf/source_context.proto"),
141 "WellKnownTypes/SourceContext.cs",
142 "../csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs");
143 generate_test.Run(importer.Import("google/protobuf/struct.proto"),
144 "WellKnownTypes/Struct.cs",
145 "../csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs");
146 generate_test.Run(importer.Import("google/protobuf/timestamp.proto"),
147 "WellKnownTypes/Timestamp.cs",
148 "../csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs");
149 generate_test.Run(importer.Import("google/protobuf/type.proto"),
150 "WellKnownTypes/Type.cs",
151 "../csharp/src/Google.Protobuf/WellKnownTypes/Type.cs");
152 generate_test.Run(importer.Import("google/protobuf/wrappers.proto"),
153 "WellKnownTypes/Wrappers.cs",
154 "../csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs");
155
156 EXPECT_EQ("", error_collector.text_);
157 }
158
159 } // namespace
160
161 } // namespace csharp
162 } // namespace compiler
163 } // namespace protobuf
164 } // namespace google
165