• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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