- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / protobuf / src / google / protobuf / compiler / mock_code_generator.cc
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
4 //
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
35 #include <google/protobuf/testing/file.h>
36 #include <google/protobuf/descriptor.pb.h>
37 #include <google/protobuf/descriptor.h>
38 #include <google/protobuf/io/zero_copy_stream.h>
39 #include <google/protobuf/io/printer.h>
40 #include <google/protobuf/stubs/strutil.h>
41 #include <google/protobuf/stubs/substitute.h>
42 #include <gtest/gtest.h>
43 #include <google/protobuf/stubs/stl_util.h>
44
45 namespace google {
46 namespace protobuf {
47 namespace compiler {
48
49 // Returns the list of the names of files in all_files in the form of a
50 // comma-separated string.
51 string CommaSeparatedList(const vector<const FileDescriptor*> all_files) {
52   vector<string> names;
53   for (int i = 0; i < all_files.size(); i++) {
54     names.push_back(all_files[i]->name());
55   }
56   return JoinStrings(names, ",");
57 }
58
59 static const char* kFirstInsertionPointName = "first_mock_insertion_point";
60 static const char* kSecondInsertionPointName = "second_mock_insertion_point";
61 static const char* kFirstInsertionPoint =
62     "# @@protoc_insertion_point(first_mock_insertion_point) is here\n";
63 static const char* kSecondInsertionPoint =
64     "  # @@protoc_insertion_point(second_mock_insertion_point) is here\n";
65
66 MockCodeGenerator::MockCodeGenerator(const string& name)
67     : name_(name) {}
68
69 MockCodeGenerator::~MockCodeGenerator() {}
70
71 void MockCodeGenerator::ExpectGenerated(
72     const string& name,
73     const string& parameter,
74     const string& insertions,
75     const string& file,
76     const string& first_message_name,
77     const string& first_parsed_file_name,
78     const string& output_directory) {
79   string content;
80   ASSERT_TRUE(File::ReadFileToString(
81       output_directory + "/" + GetOutputFileName(name, file), &content));
82
83   vector<string> lines;
84   SplitStringUsing(content, "\n", &lines);
85
86   while (!lines.empty() && lines.back().empty()) {
87     lines.pop_back();
88   }
89   for (int i = 0; i < lines.size(); i++) {
90     lines[i] += "\n";
91   }
92
93   vector<string> insertion_list;
94   if (!insertions.empty()) {
95     SplitStringUsing(insertions, ",", &insertion_list);
96   }
97
98   ASSERT_EQ(lines.size(), 3 + insertion_list.size() * 2);
99   EXPECT_EQ(GetOutputFileContent(name, parameter, file,
100                                  first_parsed_file_name, first_message_name),
101             lines[0]);
102
103   EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]);
104   EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]);
105
106   for (int i = 0; i < insertion_list.size(); i++) {
107     EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert",
108                                    file, file, first_message_name),
109               lines[1 + i]);
110     // Second insertion point is indented, so the inserted text should
111     // automatically be indented too.
112     EXPECT_EQ("  " + GetOutputFileContent(insertion_list[i], "second_insert",
113                                           file, file, first_message_name),
114               lines[2 + insertion_list.size() + i]);
115   }
116 }
117
118 bool MockCodeGenerator::Generate(
119     const FileDescriptor* file,
120     const string& parameter,
121     GeneratorContext* context,
122     string* error) const {
123   for (int i = 0; i < file->message_type_count(); i++) {
124     if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) {
125       string command = StripPrefixString(file->message_type(i)->name(),
126                                          "MockCodeGenerator_");
127       if (command == "Error") {
128         *error = "Saw message type MockCodeGenerator_Error.";
129         return false;
130       } else if (command == "Exit") {
131         cerr << "Saw message type MockCodeGenerator_Exit." << endl;
132         exit(123);
133       } else if (command == "Abort") {
134         cerr << "Saw message type MockCodeGenerator_Abort." << endl;
135         abort();
136       } else if (command == "HasSourceCodeInfo") {
137         FileDescriptorProto file_descriptor_proto;
138         file->CopySourceCodeInfoTo(&file_descriptor_proto);
139         bool has_source_code_info =
140             file_descriptor_proto.has_source_code_info() &&
141             file_descriptor_proto.source_code_info().location_size() > 0;
142         cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
143              << has_source_code_info << "." << endl;
144         abort();
145       } else {
146         GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
147       }
148     }
149   }
150
151   if (HasPrefixString(parameter, "insert=")) {
152     vector<string> insert_into;
153     SplitStringUsing(StripPrefixString(parameter, "insert="),
154                      ",", &insert_into);
155
156     for (int i = 0; i < insert_into.size(); i++) {
157       {
158         scoped_ptr<io::ZeroCopyOutputStream> output(
159             context->OpenForInsert(
160               GetOutputFileName(insert_into[i], file),
161               kFirstInsertionPointName));
162         io::Printer printer(output.get(), '$');
163         printer.PrintRaw(GetOutputFileContent(name_, "first_insert",
164                                               file, context));
165         if (printer.failed()) {
166           *error = "MockCodeGenerator detected write error.";
167           return false;
168         }
169       }
170
171       {
172         scoped_ptr<io::ZeroCopyOutputStream> output(
173             context->OpenForInsert(
174               GetOutputFileName(insert_into[i], file),
175               kSecondInsertionPointName));
176         io::Printer printer(output.get(), '$');
177         printer.PrintRaw(GetOutputFileContent(name_, "second_insert",
178                                               file, context));
179         if (printer.failed()) {
180           *error = "MockCodeGenerator detected write error.";
181           return false;
182         }
183       }
184     }
185   } else {
186     scoped_ptr<io::ZeroCopyOutputStream> output(
187         context->Open(GetOutputFileName(name_, file)));
188
189     io::Printer printer(output.get(), '$');
190     printer.PrintRaw(GetOutputFileContent(name_, parameter,
191                                           file, context));
192     printer.PrintRaw(kFirstInsertionPoint);
193     printer.PrintRaw(kSecondInsertionPoint);
194
195     if (printer.failed()) {
196       *error = "MockCodeGenerator detected write error.";
197       return false;
198     }
199   }
200
201   return true;
202 }
203
204 string MockCodeGenerator::GetOutputFileName(const string& generator_name,
205                                             const FileDescriptor* file) {
206   return GetOutputFileName(generator_name, file->name());
207 }
208
209 string MockCodeGenerator::GetOutputFileName(const string& generator_name,
210                                             const string& file) {
211   return file + ".MockCodeGenerator." + generator_name;
212 }
213
214 string MockCodeGenerator::GetOutputFileContent(
215     const string& generator_name,
216     const string& parameter,
217     const FileDescriptor* file,
218     GeneratorContext *context) {
219   vector<const FileDescriptor*> all_files;
220   context->ListParsedFiles(&all_files);
221   return GetOutputFileContent(
222       generator_name, parameter, file->name(),
223       CommaSeparatedList(all_files),
224       file->message_type_count() > 0 ?
225           file->message_type(0)->name() : "(none)");
226 }
227
228 string MockCodeGenerator::GetOutputFileContent(
229     const string& generator_name,
230     const string& parameter,
231     const string& file,
232     const string& parsed_file_list,
233     const string& first_message_name) {
234   return strings::Substitute("$0: $1, $2, $3, $4\n",
235       generator_name, parameter, file,
236       first_message_name, parsed_file_list);
237 }
238
239 }  // namespace compiler
240 }  // namespace protobuf
241 }  // namespace google