blob: 121d917b931a3b75a22da962fea91e25421f08e3 [file] [log] [blame]
kenton@google.com5e744ff2009-12-18 04:51:42 +00001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
kenton@google.com5e744ff2009-12-18 04:51:42 +00004//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// Author: kenton@google.com (Kenton Varda)
32
33#include <google/protobuf/compiler/mock_code_generator.h>
34
jieluo@google.com4de8f552014-07-18 00:47:59 +000035#include <memory>
Feng Xiao6ef984a2014-11-10 17:34:54 -080036#ifndef _SHARED_PTR_H
37#include <google/protobuf/stubs/shared_ptr.h>
38#endif
jieluo@google.com4de8f552014-07-18 00:47:59 +000039
kenton@google.com5e744ff2009-12-18 04:51:42 +000040#include <google/protobuf/testing/file.h>
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000041#include <google/protobuf/descriptor.pb.h>
kenton@google.com5e744ff2009-12-18 04:51:42 +000042#include <google/protobuf/descriptor.h>
43#include <google/protobuf/io/zero_copy_stream.h>
44#include <google/protobuf/io/printer.h>
45#include <google/protobuf/stubs/strutil.h>
46#include <google/protobuf/stubs/substitute.h>
47#include <gtest/gtest.h>
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000048#include <google/protobuf/stubs/stl_util.h>
kenton@google.com5e744ff2009-12-18 04:51:42 +000049
50namespace google {
51namespace protobuf {
52namespace compiler {
53
liujisi@google.com33165fe2010-11-02 13:14:58 +000054// Returns the list of the names of files in all_files in the form of a
55// comma-separated string.
56string CommaSeparatedList(const vector<const FileDescriptor*> all_files) {
57 vector<string> names;
58 for (int i = 0; i < all_files.size(); i++) {
59 names.push_back(all_files[i]->name());
60 }
jieluo@google.com4de8f552014-07-18 00:47:59 +000061 return Join(names, ",");
liujisi@google.com33165fe2010-11-02 13:14:58 +000062}
63
kenton@google.com5e744ff2009-12-18 04:51:42 +000064static const char* kFirstInsertionPointName = "first_mock_insertion_point";
65static const char* kSecondInsertionPointName = "second_mock_insertion_point";
66static const char* kFirstInsertionPoint =
67 "# @@protoc_insertion_point(first_mock_insertion_point) is here\n";
68static const char* kSecondInsertionPoint =
kenton@google.com5f121642009-12-23 07:03:06 +000069 " # @@protoc_insertion_point(second_mock_insertion_point) is here\n";
kenton@google.com5e744ff2009-12-18 04:51:42 +000070
71MockCodeGenerator::MockCodeGenerator(const string& name)
72 : name_(name) {}
73
74MockCodeGenerator::~MockCodeGenerator() {}
75
76void MockCodeGenerator::ExpectGenerated(
77 const string& name,
78 const string& parameter,
79 const string& insertions,
80 const string& file,
81 const string& first_message_name,
liujisi@google.com33165fe2010-11-02 13:14:58 +000082 const string& first_parsed_file_name,
kenton@google.com5e744ff2009-12-18 04:51:42 +000083 const string& output_directory) {
84 string content;
jieluo@google.com4de8f552014-07-18 00:47:59 +000085 GOOGLE_CHECK_OK(
86 File::GetContents(output_directory + "/" + GetOutputFileName(name, file),
87 &content, true));
kenton@google.com5e744ff2009-12-18 04:51:42 +000088
jieluo@google.com4de8f552014-07-18 00:47:59 +000089 vector<string> lines = Split(content, "\n", true);
kenton@google.com5e744ff2009-12-18 04:51:42 +000090
91 while (!lines.empty() && lines.back().empty()) {
92 lines.pop_back();
93 }
94 for (int i = 0; i < lines.size(); i++) {
95 lines[i] += "\n";
96 }
97
98 vector<string> insertion_list;
99 if (!insertions.empty()) {
100 SplitStringUsing(insertions, ",", &insertion_list);
101 }
102
jieluo@google.com4de8f552014-07-18 00:47:59 +0000103 EXPECT_EQ(lines.size(), 3 + insertion_list.size() * 2);
liujisi@google.com33165fe2010-11-02 13:14:58 +0000104 EXPECT_EQ(GetOutputFileContent(name, parameter, file,
105 first_parsed_file_name, first_message_name),
kenton@google.com5e744ff2009-12-18 04:51:42 +0000106 lines[0]);
107
108 EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]);
109 EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]);
110
111 for (int i = 0; i < insertion_list.size(); i++) {
112 EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert",
liujisi@google.com33165fe2010-11-02 13:14:58 +0000113 file, file, first_message_name),
kenton@google.com5e744ff2009-12-18 04:51:42 +0000114 lines[1 + i]);
kenton@google.com5f121642009-12-23 07:03:06 +0000115 // Second insertion point is indented, so the inserted text should
116 // automatically be indented too.
117 EXPECT_EQ(" " + GetOutputFileContent(insertion_list[i], "second_insert",
liujisi@google.com33165fe2010-11-02 13:14:58 +0000118 file, file, first_message_name),
kenton@google.com5e744ff2009-12-18 04:51:42 +0000119 lines[2 + insertion_list.size() + i]);
120 }
121}
122
123bool MockCodeGenerator::Generate(
124 const FileDescriptor* file,
125 const string& parameter,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000126 GeneratorContext* context,
kenton@google.com5e744ff2009-12-18 04:51:42 +0000127 string* error) const {
128 for (int i = 0; i < file->message_type_count(); i++) {
129 if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) {
130 string command = StripPrefixString(file->message_type(i)->name(),
131 "MockCodeGenerator_");
132 if (command == "Error") {
133 *error = "Saw message type MockCodeGenerator_Error.";
134 return false;
135 } else if (command == "Exit") {
Jisi Liu885b6122015-02-28 14:51:22 -0800136 std::cerr << "Saw message type MockCodeGenerator_Exit." << std::endl;
kenton@google.com5e744ff2009-12-18 04:51:42 +0000137 exit(123);
138 } else if (command == "Abort") {
Jisi Liu885b6122015-02-28 14:51:22 -0800139 std::cerr << "Saw message type MockCodeGenerator_Abort." << std::endl;
kenton@google.com5e744ff2009-12-18 04:51:42 +0000140 abort();
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000141 } else if (command == "HasSourceCodeInfo") {
142 FileDescriptorProto file_descriptor_proto;
143 file->CopySourceCodeInfoTo(&file_descriptor_proto);
144 bool has_source_code_info =
145 file_descriptor_proto.has_source_code_info() &&
146 file_descriptor_proto.source_code_info().location_size() > 0;
Jisi Liu885b6122015-02-28 14:51:22 -0800147 std::cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
148 << has_source_code_info << "." << std::endl;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000149 abort();
Feng Xiaoe841bac2015-12-11 17:09:20 -0800150 } else if (command == "HasJsonName") {
151 FieldDescriptorProto field_descriptor_proto;
152 file->message_type(i)->field(0)->CopyTo(&field_descriptor_proto);
153 std::cerr << "Saw json_name: "
154 << field_descriptor_proto.has_json_name() << std::endl;
155 abort();
kenton@google.com5e744ff2009-12-18 04:51:42 +0000156 } else {
157 GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
158 }
159 }
160 }
161
162 if (HasPrefixString(parameter, "insert=")) {
163 vector<string> insert_into;
164 SplitStringUsing(StripPrefixString(parameter, "insert="),
165 ",", &insert_into);
166
167 for (int i = 0; i < insert_into.size(); i++) {
168 {
Feng Xiaof157a562014-11-14 11:50:31 -0800169 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->OpenForInsert(
jieluo@google.com4de8f552014-07-18 00:47:59 +0000170 GetOutputFileName(insert_into[i], file), kFirstInsertionPointName));
kenton@google.com5e744ff2009-12-18 04:51:42 +0000171 io::Printer printer(output.get(), '$');
liujisi@google.com33165fe2010-11-02 13:14:58 +0000172 printer.PrintRaw(GetOutputFileContent(name_, "first_insert",
173 file, context));
kenton@google.com5e744ff2009-12-18 04:51:42 +0000174 if (printer.failed()) {
175 *error = "MockCodeGenerator detected write error.";
176 return false;
177 }
178 }
179
180 {
Feng Xiaof157a562014-11-14 11:50:31 -0800181 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
jieluo@google.com4de8f552014-07-18 00:47:59 +0000182 context->OpenForInsert(GetOutputFileName(insert_into[i], file),
183 kSecondInsertionPointName));
kenton@google.com5e744ff2009-12-18 04:51:42 +0000184 io::Printer printer(output.get(), '$');
liujisi@google.com33165fe2010-11-02 13:14:58 +0000185 printer.PrintRaw(GetOutputFileContent(name_, "second_insert",
186 file, context));
kenton@google.com5e744ff2009-12-18 04:51:42 +0000187 if (printer.failed()) {
188 *error = "MockCodeGenerator detected write error.";
189 return false;
190 }
191 }
192 }
193 } else {
Feng Xiaof157a562014-11-14 11:50:31 -0800194 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
liujisi@google.com33165fe2010-11-02 13:14:58 +0000195 context->Open(GetOutputFileName(name_, file)));
kenton@google.com5e744ff2009-12-18 04:51:42 +0000196
197 io::Printer printer(output.get(), '$');
liujisi@google.com33165fe2010-11-02 13:14:58 +0000198 printer.PrintRaw(GetOutputFileContent(name_, parameter,
199 file, context));
kenton@google.com5e744ff2009-12-18 04:51:42 +0000200 printer.PrintRaw(kFirstInsertionPoint);
201 printer.PrintRaw(kSecondInsertionPoint);
202
203 if (printer.failed()) {
204 *error = "MockCodeGenerator detected write error.";
205 return false;
206 }
207 }
208
209 return true;
210}
211
212string MockCodeGenerator::GetOutputFileName(const string& generator_name,
213 const FileDescriptor* file) {
214 return GetOutputFileName(generator_name, file->name());
215}
216
217string MockCodeGenerator::GetOutputFileName(const string& generator_name,
218 const string& file) {
219 return file + ".MockCodeGenerator." + generator_name;
220}
221
liujisi@google.com33165fe2010-11-02 13:14:58 +0000222string MockCodeGenerator::GetOutputFileContent(
223 const string& generator_name,
224 const string& parameter,
225 const FileDescriptor* file,
226 GeneratorContext *context) {
227 vector<const FileDescriptor*> all_files;
228 context->ListParsedFiles(&all_files);
kenton@google.com5e744ff2009-12-18 04:51:42 +0000229 return GetOutputFileContent(
230 generator_name, parameter, file->name(),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000231 CommaSeparatedList(all_files),
kenton@google.com5e744ff2009-12-18 04:51:42 +0000232 file->message_type_count() > 0 ?
233 file->message_type(0)->name() : "(none)");
234}
235
236string MockCodeGenerator::GetOutputFileContent(
237 const string& generator_name,
238 const string& parameter,
239 const string& file,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000240 const string& parsed_file_list,
kenton@google.com5e744ff2009-12-18 04:51:42 +0000241 const string& first_message_name) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000242 return strings::Substitute("$0: $1, $2, $3, $4\n",
243 generator_name, parameter, file,
244 first_message_name, parsed_file_list);
kenton@google.com5e744ff2009-12-18 04:51:42 +0000245}
246
247} // namespace compiler
248} // namespace protobuf
249} // namespace google