command_line_interface_unittest.cc
Go to the documentation of this file.
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
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 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34 
35 #include <fcntl.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 
39 #ifndef _MSC_VER
40 #include <unistd.h>
41 #endif
42 #include <memory>
43 #include <vector>
44 
53 #include <google/protobuf/unittest.pb.h>
60 
63 #include <gtest/gtest.h>
64 
66 
67 namespace google {
68 namespace protobuf {
69 namespace compiler {
70 
71 #if defined(_WIN32)
72 // DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
73 // them like we do below.
75 using google::protobuf::io::win32::close;
76 using google::protobuf::io::win32::dup;
77 using google::protobuf::io::win32::dup2;
78 using google::protobuf::io::win32::open;
79 using google::protobuf::io::win32::write;
80 #endif
81 
82 // Disable the whole test when we use tcmalloc for "draconian" heap checks, in
83 // which case tcmalloc will print warnings that fail the plugin tests.
84 #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
85 
86 
87 namespace {
88 
89 bool FileExists(const std::string& path) {
90  return File::Exists(path);
91 }
92 
93 class CommandLineInterfaceTest : public testing::Test {
94  protected:
95  virtual void SetUp();
96  virtual void TearDown();
97 
98  // Runs the CommandLineInterface with the given command line. The
99  // command is automatically split on spaces, and the string "$tmpdir"
100  // is replaced with TestTempDir().
101  void Run(const std::string& command);
102  void RunWithArgs(std::vector<std::string> args);
103 
104  // -----------------------------------------------------------------
105  // Methods to set up the test (called before Run()).
106 
107  class NullCodeGenerator;
108 
109  // Normally plugins are allowed for all tests. Call this to explicitly
110  // disable them.
111  void DisallowPlugins() { disallow_plugins_ = true; }
112 
113  // Create a temp file within temp_directory_ with the given name.
114  // The containing directory is also created if necessary.
115  void CreateTempFile(const std::string& name, const std::string& contents);
116 
117  // Create a subdirectory within temp_directory_.
118  void CreateTempDir(const std::string& name);
119 
120 #ifdef PROTOBUF_OPENSOURCE
121  // Change working directory to temp directory.
122  void SwitchToTempDirectory() {
124  }
125 #else // !PROTOBUF_OPENSOURCE
126  // TODO(teboring): Figure out how to change and get working directory in
127  // google3.
128 #endif // !PROTOBUF_OPENSOURCE
129 
130  // -----------------------------------------------------------------
131  // Methods to check the test results (called after Run()).
132 
133  // Checks that no text was written to stderr during Run(), and Run()
134  // returned 0.
135  void ExpectNoErrors();
136 
137  // Checks that Run() returned non-zero and the stderr output is exactly
138  // the text given. expected_test may contain references to "$tmpdir",
139  // which will be replaced by the temporary directory path.
140  void ExpectErrorText(const std::string& expected_text);
141 
142  // Checks that Run() returned non-zero and the stderr contains the given
143  // substring.
144  void ExpectErrorSubstring(const std::string& expected_substring);
145 
146  // Checks that the captured stdout is the same as the expected_text.
147  void ExpectCapturedStdout(const std::string& expected_text);
148 
149  // Checks that Run() returned zero and the stdout contains the given
150  // substring.
151  void ExpectCapturedStdoutSubstringWithZeroReturnCode(
152  const std::string& expected_substring);
153 
154 #if defined(_WIN32) && !defined(__CYGWIN__)
155  // Returns true if ExpectErrorSubstring(expected_substring) would pass, but
156  // does not fail otherwise.
157  bool HasAlternateErrorSubstring(const std::string& expected_substring);
158 #endif // _WIN32 && !__CYGWIN__
159 
160  // Checks that MockCodeGenerator::Generate() was called in the given
161  // context (or the generator in test_plugin.cc, which produces the same
162  // output). That is, this tests if the generator with the given name
163  // was called with the given parameter and proto file and produced the
164  // given output file. This is checked by reading the output file and
165  // checking that it contains the content that MockCodeGenerator would
166  // generate given these inputs. message_name is the name of the first
167  // message that appeared in the proto file; this is just to make extra
168  // sure that the correct file was parsed.
169  void ExpectGenerated(const std::string& generator_name,
170  const std::string& parameter,
171  const std::string& proto_name,
172  const std::string& message_name);
173  void ExpectGenerated(const std::string& generator_name,
174  const std::string& parameter,
175  const std::string& proto_name,
176  const std::string& message_name,
177  const std::string& output_directory);
178  void ExpectGeneratedWithMultipleInputs(const std::string& generator_name,
179  const std::string& all_proto_names,
180  const std::string& proto_name,
181  const std::string& message_name);
182  void ExpectGeneratedWithInsertions(const std::string& generator_name,
183  const std::string& parameter,
184  const std::string& insertions,
185  const std::string& proto_name,
186  const std::string& message_name);
187  void CheckGeneratedAnnotations(const std::string& name,
188  const std::string& file);
189 
190 #if defined(_WIN32)
191  void ExpectNullCodeGeneratorCalled(const std::string& parameter);
192 #endif // _WIN32
193 
194 
195  void ReadDescriptorSet(const std::string& filename,
196  FileDescriptorSet* descriptor_set);
197 
198  void WriteDescriptorSet(const std::string& filename,
199  const FileDescriptorSet* descriptor_set);
200 
201  void ExpectFileContent(const std::string& filename,
202  const std::string& content);
203 
204  private:
205  // The object we are testing.
206  CommandLineInterface cli_;
207 
208  // Was DisallowPlugins() called?
210 
211  // We create a directory within TestTempDir() in order to add extra
212  // protection against accidentally deleting user files (since we recursively
213  // delete this directory during the test). This is the full path of that
214  // directory.
216 
217  // The result of Run().
219 
220  // The captured stderr output.
222 
223  // The captured stdout.
225 
226  // Pointers which need to be deleted later.
227  std::vector<CodeGenerator*> mock_generators_to_delete_;
228 
229  NullCodeGenerator* null_generator_;
230 };
231 
232 class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator {
233  public:
234  NullCodeGenerator() : called_(false) {}
235  ~NullCodeGenerator() {}
236 
237  mutable bool called_;
239 
240  // implements CodeGenerator ----------------------------------------
241  bool Generate(const FileDescriptor* file, const std::string& parameter,
242  GeneratorContext* context, std::string* error) const {
243  called_ = true;
244  parameter_ = parameter;
245  return true;
246  }
247 };
248 
249 // ===================================================================
250 
251 void CommandLineInterfaceTest::SetUp() {
252  temp_directory_ = TestTempDir() + "/proto2_cli_test_temp";
253 
254  // If the temp directory already exists, it must be left over from a
255  // previous run. Delete it.
256  if (FileExists(temp_directory_)) {
258  }
259 
260  // Create the temp directory.
262 
263  // Register generators.
264  CodeGenerator* generator = new MockCodeGenerator("test_generator");
265  mock_generators_to_delete_.push_back(generator);
266  cli_.RegisterGenerator("--test_out", "--test_opt", generator, "Test output.");
267  cli_.RegisterGenerator("-t", generator, "Test output.");
268 
269  generator = new MockCodeGenerator("alt_generator");
270  mock_generators_to_delete_.push_back(generator);
271  cli_.RegisterGenerator("--alt_out", generator, "Alt output.");
272 
273  generator = null_generator_ = new NullCodeGenerator();
274  mock_generators_to_delete_.push_back(generator);
275  cli_.RegisterGenerator("--null_out", generator, "Null output.");
276 
277 
278  disallow_plugins_ = false;
279 }
280 
281 void CommandLineInterfaceTest::TearDown() {
282  // Delete the temp directory.
283  if (FileExists(temp_directory_)) {
285  }
286 
287  // Delete all the MockCodeGenerators.
288  for (int i = 0; i < mock_generators_to_delete_.size(); i++) {
290  }
292 }
293 
294 void CommandLineInterfaceTest::Run(const std::string& command) {
295  RunWithArgs(Split(command, " ", true));
296 }
297 
298 void CommandLineInterfaceTest::RunWithArgs(std::vector<std::string> args) {
299  if (!disallow_plugins_) {
300  cli_.AllowPlugins("prefix-");
301  std::string plugin_path;
302 #ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH
303  plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH;
304 #else
305  const char* possible_paths[] = {
306  // When building with shared libraries, libtool hides the real
307  // executable
308  // in .libs and puts a fake wrapper in the current directory.
309  // Unfortunately, due to an apparent bug on Cygwin/MinGW, if one program
310  // wrapped in this way (e.g. protobuf-tests.exe) tries to execute
311  // another
312  // program wrapped in this way (e.g. test_plugin.exe), the latter fails
313  // with error code 127 and no explanation message. Presumably the
314  // problem
315  // is that the wrapper for protobuf-tests.exe set some environment
316  // variables that confuse the wrapper for test_plugin.exe. Luckily, it
317  // turns out that if we simply invoke the wrapped test_plugin.exe
318  // directly, it works -- I guess the environment variables set by the
319  // protobuf-tests.exe wrapper happen to be correct for it too. So we do
320  // that.
321  ".libs/test_plugin.exe", // Win32 w/autotool (Cygwin / MinGW)
322  "test_plugin.exe", // Other Win32 (MSVC)
323  "test_plugin", // Unix
324  };
325  for (int i = 0; i < GOOGLE_ARRAYSIZE(possible_paths); i++) {
326  if (access(possible_paths[i], F_OK) == 0) {
327  plugin_path = possible_paths[i];
328  break;
329  }
330  }
331 #endif
332 
333  if (plugin_path.empty()) {
335  << "Plugin executable not found. Plugin tests are likely to fail.";
336  } else {
337  args.push_back("--plugin=prefix-gen-plug=" + plugin_path);
338  }
339  }
340 
341  std::unique_ptr<const char*[]> argv(new const char*[args.size()]);
342 
343  for (int i = 0; i < args.size(); i++) {
344  args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true);
345  argv[i] = args[i].c_str();
346  }
347 
348  // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and
349  // stdout at the same time. Need to figure out why and add this capture back
350  // for Cygwin.
351 #if !defined(__CYGWIN__)
353 #endif
355 
356  return_code_ = cli_.Run(args.size(), argv.get());
357 
359 #if !defined(__CYGWIN__)
361 #endif
362 }
363 
364 // -------------------------------------------------------------------
365 
366 void CommandLineInterfaceTest::CreateTempFile(const std::string& name,
367  const std::string& contents) {
368  // Create parent directory, if necessary.
369  std::string::size_type slash_pos = name.find_last_of('/');
370  if (slash_pos != std::string::npos) {
371  std::string dir = name.substr(0, slash_pos);
372  if (!FileExists(temp_directory_ + "/" + dir)) {
374  0777));
375  }
376  }
377 
378  // Write file.
379  std::string full_name = temp_directory_ + "/" + name;
381  full_name, StringReplace(contents, "$tmpdir", temp_directory_, true),
382  true));
383 }
384 
385 void CommandLineInterfaceTest::CreateTempDir(const std::string& name) {
387  0777));
388 }
389 
390 // -------------------------------------------------------------------
391 
392 void CommandLineInterfaceTest::ExpectNoErrors() {
394  EXPECT_EQ("", error_text_);
395 }
396 
397 void CommandLineInterfaceTest::ExpectErrorText(
398  const std::string& expected_text) {
400  EXPECT_EQ(StringReplace(expected_text, "$tmpdir", temp_directory_, true),
401  error_text_);
402 }
403 
404 void CommandLineInterfaceTest::ExpectErrorSubstring(
405  const std::string& expected_substring) {
408 }
409 
410 #if defined(_WIN32) && !defined(__CYGWIN__)
411 bool CommandLineInterfaceTest::HasAlternateErrorSubstring(
412  const std::string& expected_substring) {
414  return error_text_.find(expected_substring) != std::string::npos;
415 }
416 #endif // _WIN32 && !__CYGWIN__
417 
418 void CommandLineInterfaceTest::ExpectGenerated(
419  const std::string& generator_name, const std::string& parameter,
420  const std::string& proto_name, const std::string& message_name) {
421  MockCodeGenerator::ExpectGenerated(generator_name, parameter, "", proto_name,
422  message_name, proto_name, temp_directory_);
423 }
424 
425 void CommandLineInterfaceTest::ExpectGenerated(
426  const std::string& generator_name, const std::string& parameter,
427  const std::string& proto_name, const std::string& message_name,
428  const std::string& output_directory) {
429  MockCodeGenerator::ExpectGenerated(generator_name, parameter, "", proto_name,
430  message_name, proto_name,
431  temp_directory_ + "/" + output_directory);
432 }
433 
434 void CommandLineInterfaceTest::ExpectGeneratedWithMultipleInputs(
435  const std::string& generator_name, const std::string& all_proto_names,
436  const std::string& proto_name, const std::string& message_name) {
437  MockCodeGenerator::ExpectGenerated(generator_name, "", "", proto_name,
438  message_name, all_proto_names,
440 }
441 
442 void CommandLineInterfaceTest::ExpectGeneratedWithInsertions(
443  const std::string& generator_name, const std::string& parameter,
444  const std::string& insertions, const std::string& proto_name,
445  const std::string& message_name) {
446  MockCodeGenerator::ExpectGenerated(generator_name, parameter, insertions,
447  proto_name, message_name, proto_name,
449 }
450 
451 void CommandLineInterfaceTest::CheckGeneratedAnnotations(
452  const std::string& name, const std::string& file) {
454 }
455 
456 #if defined(_WIN32)
457 void CommandLineInterfaceTest::ExpectNullCodeGeneratorCalled(
458  const std::string& parameter) {
459  EXPECT_TRUE(null_generator_->called_);
460  EXPECT_EQ(parameter, null_generator_->parameter_);
461 }
462 #endif // _WIN32
463 
464 
465 void CommandLineInterfaceTest::ReadDescriptorSet(
466  const std::string& filename, FileDescriptorSet* descriptor_set) {
467  std::string path = temp_directory_ + "/" + filename;
468  std::string file_contents;
469  GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
470 
471  if (!descriptor_set->ParseFromString(file_contents)) {
472  FAIL() << "Could not parse file contents: " << path;
473  }
474 }
475 
476 void CommandLineInterfaceTest::WriteDescriptorSet(
477  const std::string& filename, const FileDescriptorSet* descriptor_set) {
478  std::string binary_proto;
479  GOOGLE_CHECK(descriptor_set->SerializeToString(&binary_proto));
480  CreateTempFile(filename, binary_proto);
481 }
482 
483 void CommandLineInterfaceTest::ExpectCapturedStdout(
484  const std::string& expected_text) {
485  EXPECT_EQ(expected_text, captured_stdout_);
486 }
487 
488 void CommandLineInterfaceTest::ExpectCapturedStdoutSubstringWithZeroReturnCode(
489  const std::string& expected_substring) {
491  EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring,
493 }
494 
495 void CommandLineInterfaceTest::ExpectFileContent(const std::string& filename,
496  const std::string& content) {
497  std::string path = temp_directory_ + "/" + filename;
498  std::string file_contents;
499  GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true));
500 
501  EXPECT_EQ(StringReplace(content, "$tmpdir", temp_directory_, true),
502  file_contents);
503 }
504 
505 // ===================================================================
506 
507 TEST_F(CommandLineInterfaceTest, BasicOutput) {
508  // Test that the common case works.
509 
510  CreateTempFile("foo.proto",
511  "syntax = \"proto2\";\n"
512  "message Foo {}\n");
513 
514  Run("protocol_compiler --test_out=$tmpdir "
515  "--proto_path=$tmpdir foo.proto");
516 
517  ExpectNoErrors();
518  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
519 }
520 
521 TEST_F(CommandLineInterfaceTest, BasicOutput_DescriptorSetIn) {
522  // Test that the common case works.
523  FileDescriptorSet file_descriptor_set;
524  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
525  file_descriptor_proto->set_name("foo.proto");
526  file_descriptor_proto->add_message_type()->set_name("Foo");
527 
528  WriteDescriptorSet("foo.bin", &file_descriptor_set);
529 
530  Run("protocol_compiler --test_out=$tmpdir "
531  "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
532 
533  ExpectNoErrors();
534  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
535 }
536 
537 TEST_F(CommandLineInterfaceTest, BasicPlugin) {
538  // Test that basic plugins work.
539 
540  CreateTempFile("foo.proto",
541  "syntax = \"proto2\";\n"
542  "message Foo {}\n");
543 
544  Run("protocol_compiler --plug_out=$tmpdir "
545  "--proto_path=$tmpdir foo.proto");
546 
547  ExpectNoErrors();
548  ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
549 }
550 
551 TEST_F(CommandLineInterfaceTest, BasicPlugin_DescriptorSetIn) {
552  // Test that basic plugins work.
553 
554  FileDescriptorSet file_descriptor_set;
555  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
556  file_descriptor_proto->set_name("foo.proto");
557  file_descriptor_proto->add_message_type()->set_name("Foo");
558 
559  WriteDescriptorSet("foo.bin", &file_descriptor_set);
560 
561  Run("protocol_compiler --plug_out=$tmpdir "
562  "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
563 
564  ExpectNoErrors();
565  ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
566 }
567 
568 TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin) {
569  // Invoke a generator and a plugin at the same time.
570 
571  CreateTempFile("foo.proto",
572  "syntax = \"proto2\";\n"
573  "message Foo {}\n");
574 
575  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
576  "--proto_path=$tmpdir foo.proto");
577 
578  ExpectNoErrors();
579  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
580  ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
581 }
582 
583 TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin_DescriptorSetIn) {
584  // Invoke a generator and a plugin at the same time.
585 
586  FileDescriptorSet file_descriptor_set;
587  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
588  file_descriptor_proto->set_name("foo.proto");
589  file_descriptor_proto->add_message_type()->set_name("Foo");
590 
591  WriteDescriptorSet("foo.bin", &file_descriptor_set);
592 
593  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
594  "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
595 
596  ExpectNoErrors();
597  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
598  ExpectGenerated("test_plugin", "", "foo.proto", "Foo");
599 }
600 
601 TEST_F(CommandLineInterfaceTest, MultipleInputs) {
602  // Test parsing multiple input files.
603 
604  CreateTempFile("foo.proto",
605  "syntax = \"proto2\";\n"
606  "message Foo {}\n");
607  CreateTempFile("bar.proto",
608  "syntax = \"proto2\";\n"
609  "message Bar {}\n");
610 
611  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
612  "--proto_path=$tmpdir foo.proto bar.proto");
613 
614  ExpectNoErrors();
615  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
616  "foo.proto", "Foo");
617  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
618  "bar.proto", "Bar");
619  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
620  "foo.proto", "Foo");
621  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
622  "bar.proto", "Bar");
623 }
624 
625 TEST_F(CommandLineInterfaceTest, MultipleInputs_DescriptorSetIn) {
626  // Test parsing multiple input files.
627  FileDescriptorSet file_descriptor_set;
628 
629  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
630  file_descriptor_proto->set_name("foo.proto");
631  file_descriptor_proto->add_message_type()->set_name("Foo");
632 
633  file_descriptor_proto = file_descriptor_set.add_file();
634  file_descriptor_proto->set_name("bar.proto");
635  file_descriptor_proto->add_message_type()->set_name("Bar");
636 
637  WriteDescriptorSet("foo.bin", &file_descriptor_set);
638 
639  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
640  "--descriptor_set_in=$tmpdir/foo.bin foo.proto bar.proto");
641 
642  ExpectNoErrors();
643  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
644  "foo.proto", "Foo");
645  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
646  "bar.proto", "Bar");
647  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
648  "foo.proto", "Foo");
649  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
650  "bar.proto", "Bar");
651 }
652 
653 TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport) {
654  // Test parsing multiple input files with an import of a separate file.
655 
656  CreateTempFile("foo.proto",
657  "syntax = \"proto2\";\n"
658  "message Foo {}\n");
659  CreateTempFile("bar.proto",
660  "syntax = \"proto2\";\n"
661  "import \"baz.proto\";\n"
662  "message Bar {\n"
663  " optional Baz a = 1;\n"
664  "}\n");
665  CreateTempFile("baz.proto",
666  "syntax = \"proto2\";\n"
667  "message Baz {}\n");
668 
669  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
670  "--proto_path=$tmpdir foo.proto bar.proto");
671 
672  ExpectNoErrors();
673  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
674  "foo.proto", "Foo");
675  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
676  "bar.proto", "Bar");
677  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
678  "foo.proto", "Foo");
679  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
680  "bar.proto", "Bar");
681 }
682 
683 TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport_DescriptorSetIn) {
684  // Test parsing multiple input files with an import of a separate file.
685  FileDescriptorSet file_descriptor_set;
686 
687  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
688  file_descriptor_proto->set_name("foo.proto");
689  file_descriptor_proto->add_message_type()->set_name("Foo");
690 
691  file_descriptor_proto = file_descriptor_set.add_file();
692  file_descriptor_proto->set_name("bar.proto");
693  file_descriptor_proto->add_dependency("baz.proto");
694  DescriptorProto* message = file_descriptor_proto->add_message_type();
695  message->set_name("Bar");
696  FieldDescriptorProto* field = message->add_field();
697  field->set_type_name("Baz");
698  field->set_name("a");
699  field->set_number(1);
700 
701  WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set);
702 
703  file_descriptor_set.clear_file();
704  file_descriptor_proto = file_descriptor_set.add_file();
705  file_descriptor_proto->set_name("baz.proto");
706  file_descriptor_proto->add_message_type()->set_name("Baz");
707 
708  file_descriptor_proto = file_descriptor_set.add_file();
709  file_descriptor_proto->set_name("bat.proto");
710  file_descriptor_proto->add_dependency("baz.proto");
711  message = file_descriptor_proto->add_message_type();
712  message->set_name("Bat");
713  field = message->add_field();
714  field->set_type_name("Baz");
715  field->set_name("a");
716  field->set_number(1);
717 
718  WriteDescriptorSet("baz_and_bat.bin", &file_descriptor_set);
720  "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir "
721  "--descriptor_set_in=$0 foo.proto bar.proto",
722  std::string("$tmpdir/foo_and_bar.bin") +
723  CommandLineInterface::kPathSeparator + "$tmpdir/baz_and_bat.bin"));
724 
725  ExpectNoErrors();
726  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
727  "foo.proto", "Foo");
728  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
729  "bar.proto", "Bar");
730  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
731  "foo.proto", "Foo");
732  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
733  "bar.proto", "Bar");
734 
736  "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir "
737  "--descriptor_set_in=$0 baz.proto bat.proto",
738  std::string("$tmpdir/foo_and_bar.bin") +
739  CommandLineInterface::kPathSeparator + "$tmpdir/baz_and_bat.bin"));
740 
741  ExpectNoErrors();
742  ExpectGeneratedWithMultipleInputs("test_generator", "baz.proto,bat.proto",
743  "baz.proto", "Baz");
744  ExpectGeneratedWithMultipleInputs("test_generator", "baz.proto,bat.proto",
745  "bat.proto", "Bat");
746  ExpectGeneratedWithMultipleInputs("test_plugin", "baz.proto,bat.proto",
747  "baz.proto", "Baz");
748  ExpectGeneratedWithMultipleInputs("test_plugin", "baz.proto,bat.proto",
749  "bat.proto", "Bat");
750 }
751 
752 TEST_F(CommandLineInterfaceTest,
753  MultipleInputsWithImport_DescriptorSetIn_DuplicateFileDescriptor) {
754  // Test parsing multiple input files with an import of a separate file.
755  FileDescriptorSet file_descriptor_set;
756 
757  FileDescriptorProto foo_file_descriptor_proto;
758  foo_file_descriptor_proto.set_name("foo.proto");
759  foo_file_descriptor_proto.add_message_type()->set_name("Foo");
760 
761  file_descriptor_set.add_file()->CopyFrom(foo_file_descriptor_proto);
762 
763  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
764  file_descriptor_proto->set_name("bar.proto");
765  file_descriptor_proto->add_dependency("baz.proto");
766  file_descriptor_proto->add_dependency("foo.proto");
767  DescriptorProto* message = file_descriptor_proto->add_message_type();
768  message->set_name("Bar");
769  FieldDescriptorProto* field = message->add_field();
770  field->set_type_name("Baz");
771  field->set_name("a");
772  field->set_number(1);
773  field = message->add_field();
774  field->set_type_name("Foo");
775  field->set_name("f");
776  field->set_number(2);
777  WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set);
778 
779  file_descriptor_set.clear_file();
780  file_descriptor_set.add_file()->CopyFrom(foo_file_descriptor_proto);
781 
782  file_descriptor_proto = file_descriptor_set.add_file();
783  file_descriptor_proto->set_name("baz.proto");
784  file_descriptor_proto->add_dependency("foo.proto");
785  message = file_descriptor_proto->add_message_type();
786  message->set_name("Baz");
787  field = message->add_field();
788  field->set_type_name("Foo");
789  field->set_name("f");
790  field->set_number(1);
791  WriteDescriptorSet("foo_and_baz.bin", &file_descriptor_set);
792 
794  "protocol_compiler --test_out=$$tmpdir --plug_out=$$tmpdir "
795  "--descriptor_set_in=$0 bar.proto",
796  std::string("$tmpdir/foo_and_bar.bin") +
797  CommandLineInterface::kPathSeparator + "$tmpdir/foo_and_baz.bin"));
798 
799  ExpectNoErrors();
800  ExpectGenerated("test_generator", "", "bar.proto", "Bar");
801  ExpectGenerated("test_plugin", "", "bar.proto", "Bar");
802 }
803 
804 TEST_F(CommandLineInterfaceTest,
805  MultipleInputsWithImport_DescriptorSetIn_MissingImport) {
806  // Test parsing multiple input files with an import of a separate file.
807  FileDescriptorSet file_descriptor_set;
808 
809  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
810  file_descriptor_proto->set_name("foo.proto");
811  file_descriptor_proto->add_message_type()->set_name("Foo");
812 
813  file_descriptor_proto = file_descriptor_set.add_file();
814  file_descriptor_proto->set_name("bar.proto");
815  file_descriptor_proto->add_dependency("baz.proto");
816  DescriptorProto* message = file_descriptor_proto->add_message_type();
817  message->set_name("Bar");
818  FieldDescriptorProto* field = message->add_field();
819  field->set_type_name("Baz");
820  field->set_name("a");
821  field->set_number(1);
822 
823  WriteDescriptorSet("foo_and_bar.bin", &file_descriptor_set);
824 
825  file_descriptor_set.clear_file();
826  file_descriptor_proto = file_descriptor_set.add_file();
827  file_descriptor_proto->set_name("baz.proto");
828  file_descriptor_proto->add_message_type()->set_name("Baz");
829 
830  WriteDescriptorSet("baz.bin", &file_descriptor_set);
831  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
832  "--descriptor_set_in=$tmpdir/foo_and_bar.bin "
833  "foo.proto bar.proto");
834  ExpectErrorSubstring(
835  "bar.proto: Import \"baz.proto\" was not found or had errors.");
836  ExpectErrorSubstring("bar.proto: \"Baz\" is not defined.");
837 }
838 
839 TEST_F(CommandLineInterfaceTest, CreateDirectory) {
840  // Test that when we output to a sub-directory, it is created.
841 
842  CreateTempFile("bar/baz/foo.proto",
843  "syntax = \"proto2\";\n"
844  "message Foo {}\n");
845  CreateTempDir("out");
846  CreateTempDir("plugout");
847 
848  Run("protocol_compiler --test_out=$tmpdir/out --plug_out=$tmpdir/plugout "
849  "--proto_path=$tmpdir bar/baz/foo.proto");
850 
851  ExpectNoErrors();
852  ExpectGenerated("test_generator", "", "bar/baz/foo.proto", "Foo", "out");
853  ExpectGenerated("test_plugin", "", "bar/baz/foo.proto", "Foo", "plugout");
854 }
855 
856 TEST_F(CommandLineInterfaceTest, GeneratorParameters) {
857  // Test that generator parameters are correctly parsed from the command line.
858 
859  CreateTempFile("foo.proto",
860  "syntax = \"proto2\";\n"
861  "message Foo {}\n");
862 
863  Run("protocol_compiler --test_out=TestParameter:$tmpdir "
864  "--plug_out=TestPluginParameter:$tmpdir "
865  "--proto_path=$tmpdir foo.proto");
866 
867  ExpectNoErrors();
868  ExpectGenerated("test_generator", "TestParameter", "foo.proto", "Foo");
869  ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo");
870 }
871 
872 TEST_F(CommandLineInterfaceTest, ExtraGeneratorParameters) {
873  // Test that generator parameters specified with the option flag are
874  // correctly passed to the code generator.
875 
876  CreateTempFile("foo.proto",
877  "syntax = \"proto2\";\n"
878  "message Foo {}\n");
879  // Create the "a" and "b" sub-directories.
880  CreateTempDir("a");
881  CreateTempDir("b");
882 
883  Run("protocol_compiler "
884  "--test_opt=foo1 "
885  "--test_out=bar:$tmpdir/a "
886  "--test_opt=foo2 "
887  "--test_out=baz:$tmpdir/b "
888  "--test_opt=foo3 "
889  "--proto_path=$tmpdir foo.proto");
890 
891  ExpectNoErrors();
892  ExpectGenerated("test_generator", "bar,foo1,foo2,foo3", "foo.proto", "Foo",
893  "a");
894  ExpectGenerated("test_generator", "baz,foo1,foo2,foo3", "foo.proto", "Foo",
895  "b");
896 }
897 
898 TEST_F(CommandLineInterfaceTest, ExtraPluginParameters) {
899  // Test that generator parameters specified with the option flag are
900  // correctly passed to the code generator.
901 
902  CreateTempFile("foo.proto",
903  "syntax = \"proto2\";\n"
904  "message Foo {}\n");
905  // Create the "a" and "b" sub-directories.
906  CreateTempDir("a");
907  CreateTempDir("b");
908 
909  Run("protocol_compiler "
910  "--plug_opt=foo1 "
911  "--plug_out=bar:$tmpdir/a "
912  "--plug_opt=foo2 "
913  "--plug_out=baz:$tmpdir/b "
914  "--plug_opt=foo3 "
915  "--proto_path=$tmpdir foo.proto");
916 
917  ExpectNoErrors();
918  ExpectGenerated("test_plugin", "bar,foo1,foo2,foo3", "foo.proto", "Foo", "a");
919  ExpectGenerated("test_plugin", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b");
920 }
921 
922 TEST_F(CommandLineInterfaceTest, UnrecognizedExtraParameters) {
923  CreateTempFile("foo.proto",
924  "syntax = \"proto2\";\n"
925  "message Foo {}\n");
926 
927  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
928  "--unknown_plug_a_opt=Foo "
929  "--unknown_plug_b_opt=Bar "
930  "--proto_path=$tmpdir foo.proto");
931 
932  ExpectErrorSubstring("Unknown flag: --unknown_plug_a_opt");
933  ExpectErrorSubstring("Unknown flag: --unknown_plug_b_opt");
934 }
935 
936 TEST_F(CommandLineInterfaceTest, ExtraPluginParametersForOutParameters) {
937  // This doesn't rely on the plugin having been registred and instead that
938  // the existence of --[name]_out is enough to make the --[name]_opt valid.
939  // However, running out of process plugins found via the search path (i.e. -
940  // not pre registered with --plugin) isn't support in this test suite, so we
941  // list the options pre/post the _out directive, and then include _opt that
942  // will be unknown, and confirm the failure output is about the expected
943  // unknown directive, which means the other were accepted.
944  // NOTE: UnrecognizedExtraParameters confirms that if two unknown _opt
945  // directives appear, they both are reported.
946 
947  CreateTempFile("foo.proto",
948  "syntax = \"proto2\";\n"
949  "message Foo {}\n");
950 
951  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
952  "--xyz_opt=foo=bar --xyz_out=$tmpdir "
953  "--abc_out=$tmpdir --abc_opt=foo=bar "
954  "--unknown_plug_opt=Foo "
955  "--proto_path=$tmpdir foo.proto");
956 
957  ExpectErrorText("Unknown flag: --unknown_plug_opt\n");
958 }
959 
960 TEST_F(CommandLineInterfaceTest, Insert) {
961  // Test running a generator that inserts code into another's output.
962 
963  CreateTempFile("foo.proto",
964  "syntax = \"proto2\";\n"
965  "message Foo {}\n");
966 
967  Run("protocol_compiler "
968  "--test_out=TestParameter:$tmpdir "
969  "--plug_out=TestPluginParameter:$tmpdir "
970  "--test_out=insert=test_generator,test_plugin:$tmpdir "
971  "--plug_out=insert=test_generator,test_plugin:$tmpdir "
972  "--proto_path=$tmpdir foo.proto");
973 
974  ExpectNoErrors();
975  ExpectGeneratedWithInsertions("test_generator", "TestParameter",
976  "test_generator,test_plugin", "foo.proto",
977  "Foo");
978  ExpectGeneratedWithInsertions("test_plugin", "TestPluginParameter",
979  "test_generator,test_plugin", "foo.proto",
980  "Foo");
981 }
982 
983 TEST_F(CommandLineInterfaceTest, InsertWithAnnotationFixup) {
984  // Check that annotation spans are updated after insertions.
985 
986  CreateTempFile("foo.proto",
987  "syntax = \"proto2\";\n"
988  "message MockCodeGenerator_Annotate {}\n");
989 
990  Run("protocol_compiler "
991  "--test_out=TestParameter:$tmpdir "
992  "--plug_out=TestPluginParameter:$tmpdir "
993  "--test_out=insert=test_generator,test_plugin:$tmpdir "
994  "--plug_out=insert=test_generator,test_plugin:$tmpdir "
995  "--proto_path=$tmpdir foo.proto");
996 
997  ExpectNoErrors();
998  CheckGeneratedAnnotations("test_generator", "foo.proto");
999  CheckGeneratedAnnotations("test_plugin", "foo.proto");
1000 }
1001 
1002 #if defined(_WIN32)
1003 
1004 TEST_F(CommandLineInterfaceTest, WindowsOutputPath) {
1005  // Test that the output path can be a Windows-style path.
1006 
1007  CreateTempFile("foo.proto", "syntax = \"proto2\";\n");
1008 
1009  Run("protocol_compiler --null_out=C:\\ "
1010  "--proto_path=$tmpdir foo.proto");
1011 
1012  ExpectNoErrors();
1013  ExpectNullCodeGeneratorCalled("");
1014 }
1015 
1016 TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) {
1017  // Test that we can have a windows-style output path and a parameter.
1018 
1019  CreateTempFile("foo.proto", "syntax = \"proto2\";\n");
1020 
1021  Run("protocol_compiler --null_out=bar:C:\\ "
1022  "--proto_path=$tmpdir foo.proto");
1023 
1024  ExpectNoErrors();
1025  ExpectNullCodeGeneratorCalled("bar");
1026 }
1027 
1028 TEST_F(CommandLineInterfaceTest, TrailingBackslash) {
1029  // Test that the directories can end in backslashes. Some users claim this
1030  // doesn't work on their system.
1031 
1032  CreateTempFile("foo.proto",
1033  "syntax = \"proto2\";\n"
1034  "message Foo {}\n");
1035 
1036  Run("protocol_compiler --test_out=$tmpdir\\ "
1037  "--proto_path=$tmpdir\\ foo.proto");
1038 
1039  ExpectNoErrors();
1040  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
1041 }
1042 
1043 TEST_F(CommandLineInterfaceTest, Win32ErrorMessage) {
1044  EXPECT_EQ("The system cannot find the file specified.\r\n",
1045  Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
1046 }
1047 
1048 #endif // defined(_WIN32) || defined(__CYGWIN__)
1049 
1050 TEST_F(CommandLineInterfaceTest, PathLookup) {
1051  // Test that specifying multiple directories in the proto search path works.
1052 
1053  CreateTempFile("b/bar.proto",
1054  "syntax = \"proto2\";\n"
1055  "message Bar {}\n");
1056  CreateTempFile("a/foo.proto",
1057  "syntax = \"proto2\";\n"
1058  "import \"bar.proto\";\n"
1059  "message Foo {\n"
1060  " optional Bar a = 1;\n"
1061  "}\n");
1062  CreateTempFile("b/foo.proto", "this should not be parsed\n");
1063 
1064  Run("protocol_compiler --test_out=$tmpdir "
1065  "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto");
1066 
1067  ExpectNoErrors();
1068  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
1069 }
1070 
1071 TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) {
1072  // Same as PathLookup, but we provide the proto_path in a single flag.
1073 
1074  CreateTempFile("b/bar.proto",
1075  "syntax = \"proto2\";\n"
1076  "message Bar {}\n");
1077  CreateTempFile("a/foo.proto",
1078  "syntax = \"proto2\";\n"
1079  "import \"bar.proto\";\n"
1080  "message Foo {\n"
1081  " optional Bar a = 1;\n"
1082  "}\n");
1083  CreateTempFile("b/foo.proto", "this should not be parsed\n");
1084 
1086  "protocol_compiler --test_out=$$tmpdir --proto_path=$0 foo.proto",
1088  "$tmpdir/b"));
1089 
1090  ExpectNoErrors();
1091  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
1092 }
1093 
1094 TEST_F(CommandLineInterfaceTest, NonRootMapping) {
1095  // Test setting up a search path mapping a directory to a non-root location.
1096 
1097  CreateTempFile("foo.proto",
1098  "syntax = \"proto2\";\n"
1099  "message Foo {}\n");
1100 
1101  Run("protocol_compiler --test_out=$tmpdir "
1102  "--proto_path=bar=$tmpdir bar/foo.proto");
1103 
1104  ExpectNoErrors();
1105  ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo");
1106 }
1107 
1108 TEST_F(CommandLineInterfaceTest, PathWithEqualsSign) {
1109  // Test setting up a search path which happens to have '=' in it.
1110 
1111  CreateTempDir("with=sign");
1112  CreateTempFile("with=sign/foo.proto",
1113  "syntax = \"proto2\";\n"
1114  "message Foo {}\n");
1115 
1116  Run("protocol_compiler --test_out=$tmpdir "
1117  "--proto_path=$tmpdir/with=sign foo.proto");
1118 
1119  ExpectNoErrors();
1120  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
1121 }
1122 
1123 TEST_F(CommandLineInterfaceTest, MultipleGenerators) {
1124  // Test that we can have multiple generators and use both in one invocation,
1125  // each with a different output directory.
1126 
1127  CreateTempFile("foo.proto",
1128  "syntax = \"proto2\";\n"
1129  "message Foo {}\n");
1130  // Create the "a" and "b" sub-directories.
1131  CreateTempDir("a");
1132  CreateTempDir("b");
1133 
1134  Run("protocol_compiler "
1135  "--test_out=$tmpdir/a "
1136  "--alt_out=$tmpdir/b "
1137  "--proto_path=$tmpdir foo.proto");
1138 
1139  ExpectNoErrors();
1140  ExpectGenerated("test_generator", "", "foo.proto", "Foo", "a");
1141  ExpectGenerated("alt_generator", "", "foo.proto", "Foo", "b");
1142 }
1143 
1144 TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) {
1145  // Test that --disallow_services doesn't cause a problem when there are no
1146  // services.
1147 
1148  CreateTempFile("foo.proto",
1149  "syntax = \"proto2\";\n"
1150  "message Foo {}\n");
1151 
1152  Run("protocol_compiler --disallow_services --test_out=$tmpdir "
1153  "--proto_path=$tmpdir foo.proto");
1154 
1155  ExpectNoErrors();
1156  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
1157 }
1158 
1159 TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) {
1160  // Test that --disallow_services produces an error when there are services.
1161 
1162  CreateTempFile("foo.proto",
1163  "syntax = \"proto2\";\n"
1164  "message Foo {}\n"
1165  "service Bar {}\n");
1166 
1167  Run("protocol_compiler --disallow_services --test_out=$tmpdir "
1168  "--proto_path=$tmpdir foo.proto");
1169 
1170  ExpectErrorSubstring("foo.proto: This file contains services");
1171 }
1172 
1173 TEST_F(CommandLineInterfaceTest, AllowServicesHasService) {
1174  // Test that services work fine as long as --disallow_services is not used.
1175 
1176  CreateTempFile("foo.proto",
1177  "syntax = \"proto2\";\n"
1178  "message Foo {}\n"
1179  "service Bar {}\n");
1180 
1181  Run("protocol_compiler --test_out=$tmpdir "
1182  "--proto_path=$tmpdir foo.proto");
1183 
1184  ExpectNoErrors();
1185  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
1186 }
1187 
1188 TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing_EmptyList) {
1189  CreateTempFile("foo.proto",
1190  "syntax = \"proto2\";\n"
1191  "import \"bar.proto\";\n"
1192  "message Foo { optional Bar bar = 1; }");
1193  CreateTempFile("bar.proto",
1194  "syntax = \"proto2\";\n"
1195  "message Bar { optional string text = 1; }");
1196 
1197  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
1198  "--direct_dependencies= foo.proto");
1199 
1200  ExpectErrorText(
1201  "foo.proto: File is imported but not declared in --direct_dependencies: "
1202  "bar.proto\n");
1203 }
1204 
1205 TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing) {
1206  CreateTempFile("foo.proto",
1207  "syntax = \"proto2\";\n"
1208  "import \"bar.proto\";\n"
1209  "import \"bla.proto\";\n"
1210  "message Foo { optional Bar bar = 1; optional Bla bla = 2; }");
1211  CreateTempFile("bar.proto",
1212  "syntax = \"proto2\";\n"
1213  "message Bar { optional string text = 1; }");
1214  CreateTempFile("bla.proto",
1215  "syntax = \"proto2\";\n"
1216  "message Bla { optional int64 number = 1; }");
1217 
1218  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
1219  "--direct_dependencies=bla.proto foo.proto");
1220 
1221  ExpectErrorText(
1222  "foo.proto: File is imported but not declared in --direct_dependencies: "
1223  "bar.proto\n");
1224 }
1225 
1226 TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation) {
1227  CreateTempFile("foo.proto",
1228  "syntax = \"proto2\";\n"
1229  "import \"bar.proto\";\n"
1230  "message Foo { optional Bar bar = 1; }");
1231  CreateTempFile("bar.proto",
1232  "syntax = \"proto2\";\n"
1233  "message Bar { optional string text = 1; }");
1234 
1235  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
1236  "--direct_dependencies=bar.proto foo.proto");
1237 
1238  ExpectNoErrors();
1239 }
1240 
1241 TEST_F(CommandLineInterfaceTest, DirectDependencies_NoViolation_MultiImports) {
1242  CreateTempFile("foo.proto",
1243  "syntax = \"proto2\";\n"
1244  "import \"bar.proto\";\n"
1245  "import \"bla.proto\";\n"
1246  "message Foo { optional Bar bar = 1; optional Bla bla = 2; }");
1247  CreateTempFile("bar.proto",
1248  "syntax = \"proto2\";\n"
1249  "message Bar { optional string text = 1; }");
1250  CreateTempFile("bla.proto",
1251  "syntax = \"proto2\";\n"
1252  "message Bla { optional int64 number = 1; }");
1253 
1254  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
1255  "--direct_dependencies=bar.proto:bla.proto foo.proto");
1256 
1257  ExpectNoErrors();
1258 }
1259 
1260 TEST_F(CommandLineInterfaceTest, DirectDependencies_ProvidedMultipleTimes) {
1261  CreateTempFile("foo.proto", "syntax = \"proto2\";\n");
1262 
1263  Run("protocol_compiler --test_out=$tmpdir --proto_path=$tmpdir "
1264  "--direct_dependencies=bar.proto --direct_dependencies=bla.proto "
1265  "foo.proto");
1266 
1267  ExpectErrorText(
1268  "--direct_dependencies may only be passed once. To specify multiple "
1269  "direct dependencies, pass them all as a single parameter separated by "
1270  "':'.\n");
1271 }
1272 
1273 TEST_F(CommandLineInterfaceTest, DirectDependencies_CustomErrorMessage) {
1274  CreateTempFile("foo.proto",
1275  "syntax = \"proto2\";\n"
1276  "import \"bar.proto\";\n"
1277  "message Foo { optional Bar bar = 1; }");
1278  CreateTempFile("bar.proto",
1279  "syntax = \"proto2\";\n"
1280  "message Bar { optional string text = 1; }");
1281 
1282  std::vector<std::string> commands;
1283  commands.push_back("protocol_compiler");
1284  commands.push_back("--test_out=$tmpdir");
1285  commands.push_back("--proto_path=$tmpdir");
1286  commands.push_back("--direct_dependencies=");
1287  commands.push_back("--direct_dependencies_violation_msg=Bla \"%s\" Bla");
1288  commands.push_back("foo.proto");
1289  RunWithArgs(commands);
1290 
1291  ExpectErrorText("foo.proto: Bla \"bar.proto\" Bla\n");
1292 }
1293 
1294 TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) {
1295  // Test that we can accept working-directory-relative input files.
1296 
1297  CreateTempFile("foo.proto",
1298  "syntax = \"proto2\";\n"
1299  "message Foo {}\n");
1300 
1301  Run("protocol_compiler --test_out=$tmpdir "
1302  "--proto_path=$tmpdir $tmpdir/foo.proto");
1303 
1304  ExpectNoErrors();
1305  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
1306 }
1307 
1308 TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) {
1309  CreateTempFile("foo.proto",
1310  "syntax = \"proto2\";\n"
1311  "message Foo {}\n");
1312  CreateTempFile("bar.proto",
1313  "syntax = \"proto2\";\n"
1314  "import \"foo.proto\";\n"
1315  "message Bar {\n"
1316  " optional Foo foo = 1;\n"
1317  "}\n");
1318 
1319  Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
1320  "--proto_path=$tmpdir bar.proto");
1321 
1322  ExpectNoErrors();
1323 
1324  FileDescriptorSet descriptor_set;
1325  ReadDescriptorSet("descriptor_set", &descriptor_set);
1326  if (HasFatalFailure()) return;
1327  EXPECT_EQ(1, descriptor_set.file_size());
1328  EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
1329  // Descriptor set should not have source code info.
1330  EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
1331  // Descriptor set should have json_name.
1332  EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name());
1333  EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name());
1334  EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name());
1335 }
1336 
1337 TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) {
1338  CreateTempFile("foo.proto",
1339  "syntax = \"proto2\";\n"
1340  "message Foo {}\n");
1341  CreateTempFile("bar.proto",
1342  "syntax = \"proto2\";\n"
1343  "import \"foo.proto\";\n"
1344  "message Bar {\n"
1345  " optional Foo foo = 1;\n"
1346  "}\n");
1347  CreateTempFile("baz.proto",
1348  "syntax = \"proto2\";\n"
1349  "import \"foo.proto\";\n"
1350  "message Baz {\n"
1351  " optional Foo foo = 1;\n"
1352  "}\n");
1353 
1354  Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
1355  "--proto_path=$tmpdir bar.proto foo.proto bar.proto baz.proto");
1356 
1357  ExpectNoErrors();
1358 
1359  FileDescriptorSet descriptor_set;
1360  ReadDescriptorSet("descriptor_set", &descriptor_set);
1361  if (HasFatalFailure()) return;
1362  EXPECT_EQ(3, descriptor_set.file_size());
1363  // foo should come first since the output is in dependency order.
1364  // since bar and baz are unordered, they should be in command line order.
1365  EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
1366  EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
1367  EXPECT_EQ("baz.proto", descriptor_set.file(2).name());
1368  // Descriptor set should not have source code info.
1369  EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
1370  // Descriptor set should have json_name.
1371  EXPECT_EQ("Bar", descriptor_set.file(1).message_type(0).name());
1372  EXPECT_EQ("foo", descriptor_set.file(1).message_type(0).field(0).name());
1373  EXPECT_TRUE(descriptor_set.file(1).message_type(0).field(0).has_json_name());
1374 }
1375 
1376 TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
1377  CreateTempFile("foo.proto",
1378  "syntax = \"proto2\";\n"
1379  "message Foo {}\n");
1380  CreateTempFile("bar.proto",
1381  "syntax = \"proto2\";\n"
1382  "import \"foo.proto\";\n"
1383  "message Bar {\n"
1384  " optional Foo foo = 1;\n"
1385  "}\n");
1386 
1387  Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
1388  "--include_source_info --proto_path=$tmpdir bar.proto");
1389 
1390  ExpectNoErrors();
1391 
1392  FileDescriptorSet descriptor_set;
1393  ReadDescriptorSet("descriptor_set", &descriptor_set);
1394  if (HasFatalFailure()) return;
1395  EXPECT_EQ(1, descriptor_set.file_size());
1396  EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
1397  // Source code info included.
1398  EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
1399 }
1400 
1401 TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
1402  CreateTempFile("foo.proto",
1403  "syntax = \"proto2\";\n"
1404  "message Foo {}\n");
1405  CreateTempFile("bar.proto",
1406  "syntax = \"proto2\";\n"
1407  "import \"foo.proto\";\n"
1408  "message Bar {\n"
1409  " optional Foo foo = 1;\n"
1410  "}\n");
1411 
1412  Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
1413  "--include_imports --proto_path=$tmpdir bar.proto");
1414 
1415  ExpectNoErrors();
1416 
1417  FileDescriptorSet descriptor_set;
1418  ReadDescriptorSet("descriptor_set", &descriptor_set);
1419  if (HasFatalFailure()) return;
1420  EXPECT_EQ(2, descriptor_set.file_size());
1421  if (descriptor_set.file(0).name() == "bar.proto") {
1422  std::swap(descriptor_set.mutable_file()->mutable_data()[0],
1423  descriptor_set.mutable_file()->mutable_data()[1]);
1424  }
1425  EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
1426  EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
1427  // Descriptor set should not have source code info.
1428  EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
1429  EXPECT_FALSE(descriptor_set.file(1).has_source_code_info());
1430 }
1431 
1432 TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
1433  CreateTempFile("foo.proto",
1434  "syntax = \"proto2\";\n"
1435  "message Foo {}\n");
1436  CreateTempFile("bar.proto",
1437  "syntax = \"proto2\";\n"
1438  "import \"foo.proto\";\n"
1439  "message Bar {\n"
1440  " optional Foo foo = 1;\n"
1441  "}\n");
1442 
1443  Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
1444  "--include_imports --include_source_info --proto_path=$tmpdir bar.proto");
1445 
1446  ExpectNoErrors();
1447 
1448  FileDescriptorSet descriptor_set;
1449  ReadDescriptorSet("descriptor_set", &descriptor_set);
1450  if (HasFatalFailure()) return;
1451  EXPECT_EQ(2, descriptor_set.file_size());
1452  if (descriptor_set.file(0).name() == "bar.proto") {
1453  std::swap(descriptor_set.mutable_file()->mutable_data()[0],
1454  descriptor_set.mutable_file()->mutable_data()[1]);
1455  }
1456  EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
1457  EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
1458  // Source code info included.
1459  EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
1460  EXPECT_TRUE(descriptor_set.file(1).has_source_code_info());
1461 }
1462 
1463 #ifdef _WIN32
1464 // TODO(teboring): Figure out how to write test on windows.
1465 #else
1466 TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileGivenTwoInputs) {
1467  CreateTempFile("foo.proto",
1468  "syntax = \"proto2\";\n"
1469  "message Foo {}\n");
1470  CreateTempFile("bar.proto",
1471  "syntax = \"proto2\";\n"
1472  "import \"foo.proto\";\n"
1473  "message Bar {\n"
1474  " optional Foo foo = 1;\n"
1475  "}\n");
1476 
1477  Run("protocol_compiler --dependency_out=$tmpdir/manifest "
1478  "--test_out=$tmpdir --proto_path=$tmpdir bar.proto foo.proto");
1479 
1480  ExpectErrorText(
1481  "Can only process one input file when using --dependency_out=FILE.\n");
1482 }
1483 
1484 #ifdef PROTOBUF_OPENSOURCE
1485 TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) {
1486  CreateTempFile("foo.proto",
1487  "syntax = \"proto2\";\n"
1488  "message Foo {}\n");
1489  CreateTempFile("bar.proto",
1490  "syntax = \"proto2\";\n"
1491  "import \"foo.proto\";\n"
1492  "message Bar {\n"
1493  " optional Foo foo = 1;\n"
1494  "}\n");
1495 
1496  std::string current_working_directory = getcwd(NULL, 0);
1497  SwitchToTempDirectory();
1498 
1499  Run("protocol_compiler --dependency_out=manifest --test_out=. "
1500  "bar.proto");
1501 
1502  ExpectNoErrors();
1503 
1504  ExpectFileContent("manifest",
1505  "bar.proto.MockCodeGenerator.test_generator: "
1506  "foo.proto\\\n bar.proto");
1507 
1508  File::ChangeWorkingDirectory(current_working_directory);
1509 }
1510 #else // !PROTOBUF_OPENSOURCE
1511 // TODO(teboring): Figure out how to change and get working directory in
1512 // google3.
1513 #endif // !PROTOBUF_OPENSOURCE
1514 
1515 TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) {
1516  CreateTempFile("foo.proto",
1517  "syntax = \"proto2\";\n"
1518  "message Foo {}\n");
1519  CreateTempFile("bar.proto",
1520  "syntax = \"proto2\";\n"
1521  "import \"foo.proto\";\n"
1522  "message Bar {\n"
1523  " optional Foo foo = 1;\n"
1524  "}\n");
1525 
1526  Run("protocol_compiler --dependency_out=$tmpdir/manifest "
1527  "--test_out=$tmpdir --proto_path=$tmpdir bar.proto");
1528 
1529  ExpectNoErrors();
1530 
1531  ExpectFileContent("manifest",
1532  "$tmpdir/bar.proto.MockCodeGenerator.test_generator: "
1533  "$tmpdir/foo.proto\\\n $tmpdir/bar.proto");
1534 }
1535 #endif // !_WIN32
1536 
1537 TEST_F(CommandLineInterfaceTest, TestArgumentFile) {
1538  // Test parsing multiple input files using an argument file.
1539 
1540  CreateTempFile("foo.proto",
1541  "syntax = \"proto2\";\n"
1542  "message Foo {}\n");
1543  CreateTempFile("bar.proto",
1544  "syntax = \"proto2\";\n"
1545  "message Bar {}\n");
1546  CreateTempFile("arguments.txt",
1547  "--test_out=$tmpdir\n"
1548  "--plug_out=$tmpdir\n"
1549  "--proto_path=$tmpdir\n"
1550  "--direct_dependencies_violation_msg=%s is not imported\n"
1551  "foo.proto\n"
1552  "bar.proto");
1553 
1554  Run("protocol_compiler @$tmpdir/arguments.txt");
1555 
1556  ExpectNoErrors();
1557  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
1558  "foo.proto", "Foo");
1559  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
1560  "bar.proto", "Bar");
1561  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
1562  "foo.proto", "Foo");
1563  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
1564  "bar.proto", "Bar");
1565 }
1566 
1567 
1568 // -------------------------------------------------------------------
1569 
1570 TEST_F(CommandLineInterfaceTest, ParseErrors) {
1571  // Test that parse errors are reported.
1572 
1573  CreateTempFile("foo.proto",
1574  "syntax = \"proto2\";\n"
1575  "badsyntax\n");
1576 
1577  Run("protocol_compiler --test_out=$tmpdir "
1578  "--proto_path=$tmpdir foo.proto");
1579 
1580  ExpectErrorText(
1581  "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n");
1582 }
1583 
1584 TEST_F(CommandLineInterfaceTest, ParseErrors_DescriptorSetIn) {
1585  // Test that parse errors are reported.
1586  CreateTempFile("foo.bin", "not a FileDescriptorSet");
1587 
1588  Run("protocol_compiler --test_out=$tmpdir "
1589  "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
1590 
1591  ExpectErrorText("$tmpdir/foo.bin: Unable to parse.\n");
1592 }
1593 
1594 TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) {
1595  // Test that parse errors are reported from multiple files.
1596 
1597  // We set up files such that foo.proto actually depends on bar.proto in
1598  // two ways: Directly and through baz.proto. bar.proto's errors should
1599  // only be reported once.
1600  CreateTempFile("bar.proto",
1601  "syntax = \"proto2\";\n"
1602  "badsyntax\n");
1603  CreateTempFile("baz.proto",
1604  "syntax = \"proto2\";\n"
1605  "import \"bar.proto\";\n");
1606  CreateTempFile("foo.proto",
1607  "syntax = \"proto2\";\n"
1608  "import \"bar.proto\";\n"
1609  "import \"baz.proto\";\n");
1610 
1611  Run("protocol_compiler --test_out=$tmpdir "
1612  "--proto_path=$tmpdir foo.proto");
1613 
1614  ExpectErrorText(
1615  "bar.proto:2:1: Expected top-level statement (e.g. \"message\").\n"
1616  "baz.proto:2:1: Import \"bar.proto\" was not found or had errors.\n"
1617  "foo.proto:2:1: Import \"bar.proto\" was not found or had errors.\n"
1618  "foo.proto:3:1: Import \"baz.proto\" was not found or had errors.\n");
1619 }
1620 
1621 TEST_F(CommandLineInterfaceTest, RecursiveImportFails) {
1622  // Create a proto file that imports itself.
1623  CreateTempFile("foo.proto",
1624  "syntax = \"proto2\";\n"
1625  "import \"foo.proto\";\n");
1626 
1627  Run("protocol_compiler --test_out=$tmpdir "
1628  "--proto_path=$tmpdir foo.proto");
1629 
1630  ExpectErrorSubstring(
1631  "foo.proto:2:1: File recursively imports itself: "
1632  "foo.proto -> foo.proto\n");
1633 }
1634 
1635 TEST_F(CommandLineInterfaceTest, InputNotFoundError) {
1636  // Test what happens if the input file is not found.
1637 
1638  Run("protocol_compiler --test_out=$tmpdir "
1639  "--proto_path=$tmpdir foo.proto");
1640 
1641  ExpectErrorText("foo.proto: No such file or directory\n");
1642 }
1643 
1644 TEST_F(CommandLineInterfaceTest, InputNotFoundError_DescriptorSetIn) {
1645  // Test what happens if the input file is not found.
1646 
1647  Run("protocol_compiler --test_out=$tmpdir "
1648  "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
1649 
1650  ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
1651 }
1652 
1653 TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) {
1654  // Test what happens when a working-directory-relative input file is not
1655  // found.
1656 
1657  Run("protocol_compiler --test_out=$tmpdir "
1658  "--proto_path=$tmpdir $tmpdir/foo.proto");
1659 
1660  ExpectErrorText("$tmpdir/foo.proto: No such file or directory\n");
1661 }
1662 
1663 TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) {
1664  // Test what happens when a working-directory-relative input file is not
1665  // mapped to a virtual path.
1666 
1667  CreateTempFile("foo.proto",
1668  "syntax = \"proto2\";\n"
1669  "message Foo {}\n");
1670 
1671  // Create a directory called "bar" so that we can point --proto_path at it.
1672  CreateTempFile("bar/dummy", "");
1673 
1674  Run("protocol_compiler --test_out=$tmpdir "
1675  "--proto_path=$tmpdir/bar $tmpdir/foo.proto");
1676 
1677  ExpectErrorText(
1678  "$tmpdir/foo.proto: File does not reside within any path "
1679  "specified using --proto_path (or -I). You must specify a "
1680  "--proto_path which encompasses this file. Note that the "
1681  "proto_path must be an exact prefix of the .proto file "
1682  "names -- protoc is too dumb to figure out when two paths "
1683  "(e.g. absolute and relative) are equivalent (it's harder "
1684  "than you think).\n");
1685 }
1686 
1687 TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) {
1688  // Check what happens if the input file is not found *and* is not mapped
1689  // in the proto_path.
1690 
1691  // Create a directory called "bar" so that we can point --proto_path at it.
1692  CreateTempFile("bar/dummy", "");
1693 
1694  Run("protocol_compiler --test_out=$tmpdir "
1695  "--proto_path=$tmpdir/bar $tmpdir/foo.proto");
1696 
1697  ExpectErrorText("$tmpdir/foo.proto: No such file or directory\n");
1698 }
1699 
1700 TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) {
1701  // Test what happens when a working-directory-relative input file is shadowed
1702  // by another file in the virtual path.
1703 
1704  CreateTempFile("foo/foo.proto",
1705  "syntax = \"proto2\";\n"
1706  "message Foo {}\n");
1707  CreateTempFile("bar/foo.proto",
1708  "syntax = \"proto2\";\n"
1709  "message Bar {}\n");
1710 
1711  Run("protocol_compiler --test_out=$tmpdir "
1712  "--proto_path=$tmpdir/foo --proto_path=$tmpdir/bar "
1713  "$tmpdir/bar/foo.proto");
1714 
1715  ExpectErrorText(
1716  "$tmpdir/bar/foo.proto: Input is shadowed in the --proto_path "
1717  "by \"$tmpdir/foo/foo.proto\". Either use the latter "
1718  "file as your input or reorder the --proto_path so that the "
1719  "former file's location comes first.\n");
1720 }
1721 
1722 TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) {
1723  // Test what happens if the input file is not found.
1724 
1725  Run("protocol_compiler --test_out=$tmpdir "
1726  "--proto_path=$tmpdir/foo foo.proto");
1727 
1728  ExpectErrorText(
1729  "$tmpdir/foo: warning: directory does not exist.\n"
1730  "foo.proto: No such file or directory\n");
1731 }
1732 
1733 TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn) {
1734  Run("protocol_compiler --test_out=$tmpdir "
1735  "--proto_path=$tmpdir --descriptor_set_in=$tmpdir/foo.bin foo.proto");
1736  ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
1737 
1738  Run("protocol_compiler --test_out=$tmpdir "
1739  "--descriptor_set_in=$tmpdir/foo.bin --proto_path=$tmpdir foo.proto");
1740  ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
1741 }
1742 
1743 TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn_CompileFiles) {
1744  // Test what happens if a proto is in a --descriptor_set_in and also exists
1745  // on disk.
1746  FileDescriptorSet file_descriptor_set;
1747 
1748  // NOTE: This file desc SHOULD be different from the one created as a temp
1749  // to make it easier to test that the file was output instead of the
1750  // contents of the --descriptor_set_in file.
1751  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
1752  file_descriptor_proto->set_name("foo.proto");
1753  file_descriptor_proto->add_message_type()->set_name("Foo");
1754 
1755  WriteDescriptorSet("foo.bin", &file_descriptor_set);
1756 
1757  CreateTempFile("foo.proto",
1758  "syntax = \"proto2\";\n"
1759  "message FooBar { required string foo_message = 1; }\n");
1760 
1761  Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
1762  "--descriptor_set_in=$tmpdir/foo.bin "
1763  "--include_source_info "
1764  "--proto_path=$tmpdir foo.proto");
1765 
1766  ExpectNoErrors();
1767 
1768  FileDescriptorSet descriptor_set;
1769  ReadDescriptorSet("descriptor_set", &descriptor_set);
1770 
1771  EXPECT_EQ(1, descriptor_set.file_size());
1772  EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
1773  // Descriptor set SHOULD have source code info.
1774  EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
1775 
1776  EXPECT_EQ("FooBar", descriptor_set.file(0).message_type(0).name());
1777  EXPECT_EQ("foo_message",
1778  descriptor_set.file(0).message_type(0).field(0).name());
1779 }
1780 
1781 TEST_F(CommandLineInterfaceTest, ProtoPathAndDependencyOut) {
1782  Run("protocol_compiler --test_out=$tmpdir "
1783  "--dependency_out=$tmpdir/manifest "
1784  "--descriptor_set_in=$tmpdir/foo.bin foo.proto");
1785  ExpectErrorText(
1786  "--descriptor_set_in cannot be used with --dependency_out.\n");
1787 
1788  Run("protocol_compiler --test_out=$tmpdir "
1789  "--descriptor_set_in=$tmpdir/foo.bin "
1790  "--dependency_out=$tmpdir/manifest foo.proto");
1791  ExpectErrorText(
1792  "--dependency_out cannot be used with --descriptor_set_in.\n");
1793 }
1794 
1795 TEST_F(CommandLineInterfaceTest, MissingInputError) {
1796  // Test that we get an error if no inputs are given.
1797 
1798  Run("protocol_compiler --test_out=$tmpdir "
1799  "--proto_path=$tmpdir");
1800 
1801  ExpectErrorText("Missing input file.\n");
1802 }
1803 
1804 TEST_F(CommandLineInterfaceTest, MissingOutputError) {
1805  CreateTempFile("foo.proto",
1806  "syntax = \"proto2\";\n"
1807  "message Foo {}\n");
1808 
1809  Run("protocol_compiler --proto_path=$tmpdir foo.proto");
1810 
1811  ExpectErrorText("Missing output directives.\n");
1812 }
1813 
1814 TEST_F(CommandLineInterfaceTest, OutputWriteError) {
1815  CreateTempFile("foo.proto",
1816  "syntax = \"proto2\";\n"
1817  "message Foo {}\n");
1818 
1819  std::string output_file =
1820  MockCodeGenerator::GetOutputFileName("test_generator", "foo.proto");
1821 
1822  // Create a directory blocking our output location.
1823  CreateTempDir(output_file);
1824 
1825  Run("protocol_compiler --test_out=$tmpdir "
1826  "--proto_path=$tmpdir foo.proto");
1827 
1828  // MockCodeGenerator no longer detects an error because we actually write to
1829  // an in-memory location first, then dump to disk at the end. This is no
1830  // big deal.
1831  // ExpectErrorSubstring("MockCodeGenerator detected write error.");
1832 
1833 #if defined(_WIN32) && !defined(__CYGWIN__)
1834  // Windows with MSVCRT.dll produces EPERM instead of EISDIR.
1835  if (HasAlternateErrorSubstring(output_file + ": Permission denied")) {
1836  return;
1837  }
1838 #endif
1839 
1840  ExpectErrorSubstring(output_file + ": Is a directory");
1841 }
1842 
1843 TEST_F(CommandLineInterfaceTest, PluginOutputWriteError) {
1844  CreateTempFile("foo.proto",
1845  "syntax = \"proto2\";\n"
1846  "message Foo {}\n");
1847 
1848  std::string output_file =
1849  MockCodeGenerator::GetOutputFileName("test_plugin", "foo.proto");
1850 
1851  // Create a directory blocking our output location.
1852  CreateTempDir(output_file);
1853 
1854  Run("protocol_compiler --plug_out=$tmpdir "
1855  "--proto_path=$tmpdir foo.proto");
1856 
1857 #if defined(_WIN32) && !defined(__CYGWIN__)
1858  // Windows with MSVCRT.dll produces EPERM instead of EISDIR.
1859  if (HasAlternateErrorSubstring(output_file + ": Permission denied")) {
1860  return;
1861  }
1862 #endif
1863 
1864  ExpectErrorSubstring(output_file + ": Is a directory");
1865 }
1866 
1867 TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) {
1868  CreateTempFile("foo.proto",
1869  "syntax = \"proto2\";\n"
1870  "message Foo {}\n");
1871 
1872  Run("protocol_compiler --test_out=$tmpdir/nosuchdir "
1873  "--proto_path=$tmpdir foo.proto");
1874 
1875  ExpectErrorSubstring("nosuchdir/: No such file or directory");
1876 }
1877 
1878 TEST_F(CommandLineInterfaceTest, PluginOutputDirectoryNotFoundError) {
1879  CreateTempFile("foo.proto",
1880  "syntax = \"proto2\";\n"
1881  "message Foo {}\n");
1882 
1883  Run("protocol_compiler --plug_out=$tmpdir/nosuchdir "
1884  "--proto_path=$tmpdir foo.proto");
1885 
1886  ExpectErrorSubstring("nosuchdir/: No such file or directory");
1887 }
1888 
1889 TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) {
1890  CreateTempFile("foo.proto",
1891  "syntax = \"proto2\";\n"
1892  "message Foo {}\n");
1893 
1894  Run("protocol_compiler --test_out=$tmpdir/foo.proto "
1895  "--proto_path=$tmpdir foo.proto");
1896 
1897 #if defined(_WIN32) && !defined(__CYGWIN__)
1898  // Windows with MSVCRT.dll produces EINVAL instead of ENOTDIR.
1899  if (HasAlternateErrorSubstring("foo.proto/: Invalid argument")) {
1900  return;
1901  }
1902 #endif
1903 
1904  ExpectErrorSubstring("foo.proto/: Not a directory");
1905 }
1906 
1907 TEST_F(CommandLineInterfaceTest, GeneratorError) {
1908  CreateTempFile("foo.proto",
1909  "syntax = \"proto2\";\n"
1910  "message MockCodeGenerator_Error {}\n");
1911 
1912  Run("protocol_compiler --test_out=$tmpdir "
1913  "--proto_path=$tmpdir foo.proto");
1914 
1915  ExpectErrorSubstring(
1916  "--test_out: foo.proto: Saw message type MockCodeGenerator_Error.");
1917 }
1918 
1919 TEST_F(CommandLineInterfaceTest, GeneratorPluginError) {
1920  // Test a generator plugin that returns an error.
1921 
1922  CreateTempFile("foo.proto",
1923  "syntax = \"proto2\";\n"
1924  "message MockCodeGenerator_Error {}\n");
1925 
1926  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
1927  "--proto_path=$tmpdir foo.proto");
1928 
1929  ExpectErrorSubstring(
1930  "--plug_out: foo.proto: Saw message type MockCodeGenerator_Error.");
1931 }
1932 
1933 TEST_F(CommandLineInterfaceTest, GeneratorPluginFail) {
1934  // Test a generator plugin that exits with an error code.
1935 
1936  CreateTempFile("foo.proto",
1937  "syntax = \"proto2\";\n"
1938  "message MockCodeGenerator_Exit {}\n");
1939 
1940  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
1941  "--proto_path=$tmpdir foo.proto");
1942 
1943  ExpectErrorSubstring("Saw message type MockCodeGenerator_Exit.");
1944  ExpectErrorSubstring(
1945  "--plug_out: prefix-gen-plug: Plugin failed with status code 123.");
1946 }
1947 
1948 TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) {
1949  // Test a generator plugin that crashes.
1950 
1951  CreateTempFile("foo.proto",
1952  "syntax = \"proto2\";\n"
1953  "message MockCodeGenerator_Abort {}\n");
1954 
1955  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
1956  "--proto_path=$tmpdir foo.proto");
1957 
1958  ExpectErrorSubstring("Saw message type MockCodeGenerator_Abort.");
1959 
1960 #ifdef _WIN32
1961  // Windows doesn't have signals. It looks like abort()ing causes the process
1962  // to exit with status code 3, but let's not depend on the exact number here.
1963  ExpectErrorSubstring(
1964  "--plug_out: prefix-gen-plug: Plugin failed with status code");
1965 #else
1966  // Don't depend on the exact signal number.
1967  ExpectErrorSubstring("--plug_out: prefix-gen-plug: Plugin killed by signal");
1968 #endif
1969 }
1970 
1971 TEST_F(CommandLineInterfaceTest, PluginReceivesSourceCodeInfo) {
1972  CreateTempFile("foo.proto",
1973  "syntax = \"proto2\";\n"
1974  "message MockCodeGenerator_HasSourceCodeInfo {}\n");
1975 
1976  Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
1977 
1978  ExpectErrorSubstring(
1979  "Saw message type MockCodeGenerator_HasSourceCodeInfo: 1.");
1980 }
1981 
1982 TEST_F(CommandLineInterfaceTest, PluginReceivesJsonName) {
1983  CreateTempFile("foo.proto",
1984  "syntax = \"proto2\";\n"
1985  "message MockCodeGenerator_HasJsonName {\n"
1986  " optional int32 value = 1;\n"
1987  "}\n");
1988 
1989  Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
1990 
1991  ExpectErrorSubstring("Saw json_name: 1");
1992 }
1993 
1994 TEST_F(CommandLineInterfaceTest, PluginReceivesCompilerVersion) {
1995  CreateTempFile("foo.proto",
1996  "syntax = \"proto2\";\n"
1997  "message MockCodeGenerator_ShowVersionNumber {\n"
1998  " optional int32 value = 1;\n"
1999  "}\n");
2000 
2001  Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
2002 
2003  ExpectErrorSubstring(StringPrintf("Saw compiler_version: %d %s",
2006 }
2007 
2008 TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
2009  // Test what happens if the plugin isn't found.
2010 
2011  CreateTempFile("error.proto",
2012  "syntax = \"proto2\";\n"
2013  "message Foo {}\n");
2014 
2015  Run("protocol_compiler --badplug_out=TestParameter:$tmpdir "
2016  "--plugin=prefix-gen-badplug=no_such_file "
2017  "--proto_path=$tmpdir error.proto");
2018 
2019 #ifdef _WIN32
2020  ExpectErrorSubstring("--badplug_out: prefix-gen-badplug: " +
2021  Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
2022 #else
2023  // Error written to stdout by child process after exec() fails.
2024  ExpectErrorSubstring("no_such_file: program not found or is not executable");
2025 
2026  ExpectErrorSubstring(
2027  "Please specify a program using absolute path or make sure "
2028  "the program is available in your PATH system variable");
2029 
2030  // Error written by parent process when child fails.
2031  ExpectErrorSubstring(
2032  "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1.");
2033 #endif
2034 }
2035 
2036 TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) {
2037  // Test what happens if plugins aren't allowed.
2038 
2039  CreateTempFile("error.proto",
2040  "syntax = \"proto2\";\n"
2041  "message Foo {}\n");
2042 
2043  DisallowPlugins();
2044  Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
2045  "--proto_path=$tmpdir error.proto");
2046 
2047  ExpectErrorSubstring("Unknown flag: --plug_out");
2048 }
2049 
2050 TEST_F(CommandLineInterfaceTest, HelpText) {
2051  Run("test_exec_name --help");
2052 
2053  ExpectCapturedStdoutSubstringWithZeroReturnCode("Usage: test_exec_name ");
2054  ExpectCapturedStdoutSubstringWithZeroReturnCode("--test_out=OUT_DIR");
2055  ExpectCapturedStdoutSubstringWithZeroReturnCode("Test output.");
2056  ExpectCapturedStdoutSubstringWithZeroReturnCode("--alt_out=OUT_DIR");
2057  ExpectCapturedStdoutSubstringWithZeroReturnCode("Alt output.");
2058 }
2059 
2060 TEST_F(CommandLineInterfaceTest, GccFormatErrors) {
2061  // Test --error_format=gcc (which is the default, but we want to verify
2062  // that it can be set explicitly).
2063 
2064  CreateTempFile("foo.proto",
2065  "syntax = \"proto2\";\n"
2066  "badsyntax\n");
2067 
2068  Run("protocol_compiler --test_out=$tmpdir "
2069  "--proto_path=$tmpdir --error_format=gcc foo.proto");
2070 
2071  ExpectErrorText(
2072  "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n");
2073 }
2074 
2075 TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) {
2076  // Test --error_format=msvs
2077 
2078  CreateTempFile("foo.proto",
2079  "syntax = \"proto2\";\n"
2080  "badsyntax\n");
2081 
2082  Run("protocol_compiler --test_out=$tmpdir "
2083  "--proto_path=$tmpdir --error_format=msvs foo.proto");
2084 
2085  ExpectErrorText(
2086  "$tmpdir/foo.proto(2) : error in column=1: Expected top-level statement "
2087  "(e.g. \"message\").\n");
2088 }
2089 
2090 TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) {
2091  // Test --error_format=msvs
2092 
2093  CreateTempFile("foo.proto",
2094  "syntax = \"proto2\";\n"
2095  "badsyntax\n");
2096 
2097  Run("protocol_compiler --test_out=$tmpdir "
2098  "--proto_path=$tmpdir --error_format=invalid foo.proto");
2099 
2100  ExpectErrorText("Unknown error format: invalid\n");
2101 }
2102 
2103 // -------------------------------------------------------------------
2104 // Flag parsing tests
2105 
2106 TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) {
2107  // Test that a single-character flag works.
2108 
2109  CreateTempFile("foo.proto",
2110  "syntax = \"proto2\";\n"
2111  "message Foo {}\n");
2112 
2113  Run("protocol_compiler -t$tmpdir "
2114  "--proto_path=$tmpdir foo.proto");
2115 
2116  ExpectNoErrors();
2117  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
2118 }
2119 
2120 TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) {
2121  // Test that separating the flag value with a space works.
2122 
2123  CreateTempFile("foo.proto",
2124  "syntax = \"proto2\";\n"
2125  "message Foo {}\n");
2126 
2127  Run("protocol_compiler --test_out $tmpdir "
2128  "--proto_path=$tmpdir foo.proto");
2129 
2130  ExpectNoErrors();
2131  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
2132 }
2133 
2134 TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) {
2135  // Test that separating the flag value with a space works for
2136  // single-character flags.
2137 
2138  CreateTempFile("foo.proto",
2139  "syntax = \"proto2\";\n"
2140  "message Foo {}\n");
2141 
2142  Run("protocol_compiler -t $tmpdir "
2143  "--proto_path=$tmpdir foo.proto");
2144 
2145  ExpectNoErrors();
2146  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
2147 }
2148 
2149 TEST_F(CommandLineInterfaceTest, MissingValueError) {
2150  // Test that we get an error if a flag is missing its value.
2151 
2152  Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto");
2153 
2154  ExpectErrorText("Missing value for flag: --test_out\n");
2155 }
2156 
2157 TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) {
2158  // Test that we get an error if the last argument is a flag requiring a
2159  // value.
2160 
2161  Run("protocol_compiler --test_out");
2162 
2163  ExpectErrorText("Missing value for flag: --test_out\n");
2164 }
2165 
2166 TEST_F(CommandLineInterfaceTest, PrintFreeFieldNumbers) {
2167  CreateTempFile("foo.proto",
2168  "syntax = \"proto2\";\n"
2169  "package foo;\n"
2170  "message Foo {\n"
2171  " optional int32 a = 2;\n"
2172  " optional string b = 4;\n"
2173  " optional string c = 5;\n"
2174  " optional int64 d = 8;\n"
2175  " optional double e = 10;\n"
2176  "}\n");
2177  CreateTempFile("bar.proto",
2178  "syntax = \"proto2\";\n"
2179  "message Bar {\n"
2180  " optional int32 a = 2;\n"
2181  " extensions 4 to 5;\n"
2182  " optional int64 d = 8;\n"
2183  " extensions 10;\n"
2184  "}\n");
2185  CreateTempFile("baz.proto",
2186  "syntax = \"proto2\";\n"
2187  "message Baz {\n"
2188  " optional int32 a = 2;\n"
2189  " optional int64 d = 8;\n"
2190  " extensions 15 to max;\n" // unordered.
2191  " extensions 13;\n"
2192  " extensions 10 to 12;\n"
2193  " extensions 5;\n"
2194  " extensions 4;\n"
2195  "}\n");
2196  CreateTempFile(
2197  "quz.proto",
2198  "syntax = \"proto2\";\n"
2199  "message Quz {\n"
2200  " message Foo {}\n" // nested message
2201  " optional int32 a = 2;\n"
2202  " optional group C = 4 {\n"
2203  " optional int32 d = 5;\n"
2204  " }\n"
2205  " extensions 8 to 10;\n"
2206  " optional group E = 11 {\n"
2207  " optional int32 f = 9;\n" // explicitly reuse extension range 8-10
2208  " optional group G = 15 {\n" // nested group
2209  " message Foo {}\n" // nested message inside nested group
2210  " }\n"
2211  " }\n"
2212  "}\n");
2213 
2214  Run("protocol_compiler --print_free_field_numbers --proto_path=$tmpdir "
2215  "foo.proto bar.proto baz.proto quz.proto");
2216 
2217  ExpectNoErrors();
2218 
2219  // TODO(jieluo): Cygwin doesn't work well if we try to capture stderr and
2220  // stdout at the same time. Need to figure out why and add this test back
2221  // for Cygwin.
2222 #if !defined(__CYGWIN__)
2223  ExpectCapturedStdout(
2224  "foo.Foo free: 1 3 6-7 9 11-INF\n"
2225  "Bar free: 1 3 6-7 9 11-INF\n"
2226  "Baz free: 1 3 6-7 9 14\n"
2227  "Quz.Foo free: 1-INF\n"
2228  "Quz.E.G.Foo free: 1-INF\n"
2229  "Quz free: 1 3 6-7 12-14 16-INF\n");
2230 #endif
2231 }
2232 
2233 // ===================================================================
2234 
2235 // Test for --encode and --decode. Note that it would be easier to do this
2236 // test as a shell script, but we'd like to be able to run the test on
2237 // platforms that don't have a Bourne-compatible shell available (especially
2238 // Windows/MSVC).
2239 
2240 enum EncodeDecodeTestMode { PROTO_PATH, DESCRIPTOR_SET_IN };
2241 
2242 class EncodeDecodeTest : public testing::TestWithParam<EncodeDecodeTestMode> {
2243  protected:
2244  virtual void SetUp() {
2245  WriteUnittestProtoDescriptorSet();
2246  duped_stdin_ = dup(STDIN_FILENO);
2247  }
2248 
2249  virtual void TearDown() {
2250  dup2(duped_stdin_, STDIN_FILENO);
2251  close(duped_stdin_);
2252  }
2253 
2254  void RedirectStdinFromText(const std::string& input) {
2255  std::string filename = TestTempDir() + "/test_stdin";
2256  GOOGLE_CHECK_OK(File::SetContents(filename, input, true));
2257  GOOGLE_CHECK(RedirectStdinFromFile(filename));
2258  }
2259 
2260  bool RedirectStdinFromFile(const std::string& filename) {
2261  int fd = open(filename.c_str(), O_RDONLY);
2262  if (fd < 0) return false;
2263  dup2(fd, STDIN_FILENO);
2264  close(fd);
2265  return true;
2266  }
2267 
2268  // Remove '\r' characters from text.
2269  std::string StripCR(const std::string& text) {
2270  std::string result;
2271 
2272  for (int i = 0; i < text.size(); i++) {
2273  if (text[i] != '\r') {
2274  result.push_back(text[i]);
2275  }
2276  }
2277 
2278  return result;
2279  }
2280 
2281  enum Type { TEXT, BINARY };
2282  enum ReturnCode { SUCCESS, ERROR };
2283 
2284  bool Run(const std::string& command) {
2285  std::vector<std::string> args;
2286  args.push_back("protoc");
2287  SplitStringUsing(command, " ", &args);
2288  switch (GetParam()) {
2289  case PROTO_PATH:
2290  args.push_back("--proto_path=" + TestUtil::TestSourceDir());
2291  break;
2292  case DESCRIPTOR_SET_IN:
2293  args.push_back(StrCat("--descriptor_set_in=",
2295  break;
2296  default:
2297  ADD_FAILURE() << "unexpected EncodeDecodeTestMode: " << GetParam();
2298  }
2299 
2300  std::unique_ptr<const char*[]> argv(new const char*[args.size()]);
2301  for (int i = 0; i < args.size(); i++) {
2302  argv[i] = args[i].c_str();
2303  }
2304 
2305  CommandLineInterface cli;
2306 
2309 
2310  int result = cli.Run(args.size(), argv.get());
2311 
2314 
2315  return result == 0;
2316  }
2317 
2318  void ExpectStdoutMatchesBinaryFile(const std::string& filename) {
2319  std::string expected_output;
2320  GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
2321 
2322  // Don't use EXPECT_EQ because we don't want to print raw binary data to
2323  // stdout on failure.
2324  EXPECT_TRUE(captured_stdout_ == expected_output);
2325  }
2326 
2327  void ExpectStdoutMatchesTextFile(const std::string& filename) {
2328  std::string expected_output;
2329  GOOGLE_CHECK_OK(File::GetContents(filename, &expected_output, true));
2330 
2331  ExpectStdoutMatchesText(expected_output);
2332  }
2333 
2334  void ExpectStdoutMatchesText(const std::string& expected_text) {
2335  EXPECT_EQ(StripCR(expected_text), StripCR(captured_stdout_));
2336  }
2337 
2338  void ExpectStderrMatchesText(const std::string& expected_text) {
2339  EXPECT_EQ(StripCR(expected_text), StripCR(captured_stderr_));
2340  }
2341 
2342  private:
2343  void WriteUnittestProtoDescriptorSet() {
2345  TestTempDir() + "/unittest_proto_descriptor_set.bin";
2346  FileDescriptorSet file_descriptor_set;
2347  protobuf_unittest::TestAllTypes test_all_types;
2348  test_all_types.descriptor()->file()->CopyTo(file_descriptor_set.add_file());
2349 
2350  protobuf_unittest_import::ImportMessage import_message;
2351  import_message.descriptor()->file()->CopyTo(file_descriptor_set.add_file());
2352 
2353  protobuf_unittest_import::PublicImportMessage public_import_message;
2354  public_import_message.descriptor()->file()->CopyTo(
2355  file_descriptor_set.add_file());
2356  GOOGLE_DCHECK(file_descriptor_set.IsInitialized());
2357 
2358  std::string binary_proto;
2359  GOOGLE_CHECK(file_descriptor_set.SerializeToString(&binary_proto));
2361  binary_proto, true));
2362  }
2363 
2368 };
2369 
2370 TEST_P(EncodeDecodeTest, Encode) {
2371  RedirectStdinFromFile(TestUtil::GetTestDataPath(
2372  "net/proto2/internal/"
2373  "testdata/text_format_unittest_data_oneof_implemented.txt"));
2374  EXPECT_TRUE(
2375  Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
2376  " --encode=protobuf_unittest.TestAllTypes"));
2377  ExpectStdoutMatchesBinaryFile(TestUtil::GetTestDataPath(
2378  "net/proto2/internal/testdata/golden_message_oneof_implemented"));
2379  ExpectStderrMatchesText("");
2380 }
2381 
2382 TEST_P(EncodeDecodeTest, Decode) {
2383  RedirectStdinFromFile(TestUtil::GetTestDataPath(
2384  "net/proto2/internal/testdata/golden_message_oneof_implemented"));
2385  EXPECT_TRUE(
2386  Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
2387  " --decode=protobuf_unittest.TestAllTypes"));
2388  ExpectStdoutMatchesTextFile(TestUtil::GetTestDataPath(
2389  "net/proto2/internal/"
2390  "testdata/text_format_unittest_data_oneof_implemented.txt"));
2391  ExpectStderrMatchesText("");
2392 }
2393 
2394 TEST_P(EncodeDecodeTest, Partial) {
2395  RedirectStdinFromText("");
2396  EXPECT_TRUE(
2397  Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
2398  " --encode=protobuf_unittest.TestRequired"));
2399  ExpectStdoutMatchesText("");
2400  ExpectStderrMatchesText(
2401  "warning: Input message is missing required fields: a, b, c\n");
2402 }
2403 
2404 TEST_P(EncodeDecodeTest, DecodeRaw) {
2405  protobuf_unittest::TestAllTypes message;
2406  message.set_optional_int32(123);
2407  message.set_optional_string("foo");
2408  std::string data;
2409  message.SerializeToString(&data);
2410 
2411  RedirectStdinFromText(data);
2412  EXPECT_TRUE(Run("--decode_raw"));
2413  ExpectStdoutMatchesText(
2414  "1: 123\n"
2415  "14: \"foo\"\n");
2416  ExpectStderrMatchesText("");
2417 }
2418 
2419 TEST_P(EncodeDecodeTest, UnknownType) {
2420  EXPECT_FALSE(
2421  Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
2422  " --encode=NoSuchType"));
2423  ExpectStdoutMatchesText("");
2424  ExpectStderrMatchesText("Type not defined: NoSuchType\n");
2425 }
2426 
2427 TEST_P(EncodeDecodeTest, ProtoParseError) {
2428  EXPECT_FALSE(
2429  Run("net/proto2/internal/no_such_file.proto "
2430  "--encode=NoSuchType"));
2431  ExpectStdoutMatchesText("");
2432  ExpectStderrMatchesText(
2433  "net/proto2/internal/no_such_file.proto: No such file or directory\n");
2434 }
2435 
2436 INSTANTIATE_TEST_SUITE_P(FileDescriptorSetSource, EncodeDecodeTest,
2437  testing::Values(PROTO_PATH, DESCRIPTOR_SET_IN));
2438 } // anonymous namespace
2439 
2440 #endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
2441 
2442 } // namespace compiler
2443 } // namespace protobuf
2444 } // namespace google
FileDescriptorSet::clear_file
void clear_file()
Definition: descriptor.pb.h:6538
zero_copy_stream.h
FileDescriptorProto::add_message_type
PROTOBUF_NAMESPACE_ID::DescriptorProto * add_message_type()
Definition: descriptor.pb.h:6873
google::protobuf::GetCapturedTestStderr
string GetCapturedTestStderr()
Definition: googletest.cc:245
ADD_FAILURE
#define ADD_FAILURE()
Definition: gtest.h:1938
FileDescriptorSet::add_file
PROTOBUF_NAMESPACE_ID::FileDescriptorProto * add_file()
Definition: descriptor.pb.h:6554
name
GLuint const GLchar * name
Definition: glcorearb.h:3055
google::protobuf::File::SetContents
static bool SetContents(const string &name, const string &contents, bool)
Definition: file.h:93
google::protobuf::compiler::CommandLineInterface::RegisterGenerator
void RegisterGenerator(const std::string &flag_name, CodeGenerator *generator, const std::string &help_text)
Definition: command_line_interface.cc:797
google::protobuf::GetCapturedTestStdout
string GetCapturedTestStdout()
Definition: googletest.cc:230
FAIL
#define FAIL()
Definition: gtest.h:1952
NULL
NULL
Definition: test_security_zap.cpp:405
google::protobuf::StrCat
string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: strutil.cc:1480
input
std::string input
Definition: tokenizer_unittest.cc:197
google::protobuf::INSTANTIATE_TEST_SUITE_P
INSTANTIATE_TEST_SUITE_P(UseArena, DynamicMessageTest, ::testing::Bool())
gtest.h
GOOGLE_DCHECK
#define GOOGLE_DCHECK
Definition: logging.h:194
FieldDescriptorProto
Definition: descriptor.pb.h:1678
FileDescriptor
Definition: ruby/ext/google/protobuf_c/protobuf.h:125
EXPECT_EQ
#define EXPECT_EQ(val1, val2)
Definition: glog/src/googletest.h:155
FileDescriptorProto::add_dependency
std::string * add_dependency()
Definition: descriptor.pb.h:6761
string
GLsizei const GLchar *const * string
Definition: glcorearb.h:3083
FileDescriptorSet::IsInitialized
bool IsInitialized() const final
Definition: descriptor.pb.cc:1645
google::protobuf::compiler::CommandLineInterface::Run
int Run(int argc, const char *const argv[])
Definition: command_line_interface.cc:823
google::protobuf::CaptureTestStdout
void CaptureTestStdout()
Definition: googletest.cc:200
error
Definition: cJSON.c:88
testing::Test
Definition: gtest.h:415
mock_generators_to_delete_
std::vector< CodeGenerator * > mock_generators_to_delete_
Definition: command_line_interface_unittest.cc:227
testing::TestWithParam
Definition: gtest.h:1910
subprocess.h
disallow_plugins_
bool disallow_plugins_
Definition: command_line_interface_unittest.cc:209
mock_code_generator.h
test_util2.h
GOOGLE_ARRAYSIZE
#define GOOGLE_ARRAYSIZE(a)
Definition: macros.h:88
google::protobuf::TEST_P
TEST_P(DynamicMessageTest, IndependentOffsets)
Definition: dynamic_message_unittest.cc:143
access
GLuint GLint GLboolean GLint GLenum access
Definition: glcorearb.h:4266
captured_stderr_
std::string captured_stderr_
Definition: command_line_interface_unittest.cc:2366
google::protobuf::CaptureTestStderr
void CaptureTestStderr()
Definition: googletest.cc:215
captured_stdout_
std::string captured_stdout_
Definition: command_line_interface_unittest.cc:224
strutil.h
Type
Definition: type.pb.h:182
google::protobuf::File::GetContents
static bool GetContents(const string &name, string *output, bool)
Definition: file.h:83
path
GLsizei const GLchar ** path
Definition: glcorearb.h:3658
FileDescriptorProto::set_name
void set_name(const std::string &value)
Definition: descriptor.pb.h:6580
EXPECT_NE
#define EXPECT_NE(val1, val2)
Definition: glog/src/googletest.h:156
google::protobuf::TestUtil::GetTestDataPath
std::string GetTestDataPath(const std::string &google3_path)
Definition: test_util2.h:66
error_text_
std::string error_text_
Definition: command_line_interface_unittest.cc:221
FileDescriptorSet::file
const PROTOBUF_NAMESPACE_ID::FileDescriptorProto & file(int index) const
Definition: descriptor.pb.h:6550
printer.h
GOOGLE_LOG
#define GOOGLE_LOG(LEVEL)
Definition: logging.h:146
std::swap
void swap(Json::Value &a, Json::Value &b)
Specialize std::swap() for Json::Value.
Definition: json.h:1226
google::protobuf::TestUtil::MaybeTranslatePath
std::string MaybeTranslatePath(const std::string &google3_path)
Definition: test_util2.h:56
temp_directory_
std::string temp_directory_
Definition: command_line_interface_unittest.cc:215
null_generator_
NullCodeGenerator * null_generator_
Definition: command_line_interface_unittest.cc:229
google::protobuf::strings::Substitute
string Substitute(const char *format, const SubstituteArg &arg0, const SubstituteArg &arg1, const SubstituteArg &arg2, const SubstituteArg &arg3, const SubstituteArg &arg4, const SubstituteArg &arg5, const SubstituteArg &arg6, const SubstituteArg &arg7, const SubstituteArg &arg8, const SubstituteArg &arg9)
Definition: substitute.cc:55
code_generator.h
EXPECT_TRUE
#define EXPECT_TRUE(cond)
Definition: glog/src/googletest.h:137
FileDescriptorProto
Definition: descriptor.pb.h:501
google::protobuf::StringPrintf
string StringPrintf(const char *format,...)
Definition: stringprintf.cc:109
field
const FieldDescriptor * field
Definition: parser_unittest.cc:2694
FileDescriptorSet
Definition: descriptor.pb.h:333
google::protobuf::ERROR
static const LogLevel ERROR
Definition: protobuf/src/google/protobuf/testing/googletest.h:70
google::protobuf::compiler::MockCodeGenerator::ExpectGenerated
static void ExpectGenerated(const std::string &name, const std::string &parameter, const std::string &insertions, const std::string &file, const std::string &first_message_name, const std::string &parsed_file_list, const std::string &output_directory)
Definition: mock_code_generator.cc:90
GOOGLE_CHECK
#define GOOGLE_CHECK(EXPRESSION)
Definition: logging.h:153
FileDescriptorSet::mutable_file
PROTOBUF_NAMESPACE_ID::FileDescriptorProto * mutable_file(int index)
Definition: descriptor.pb.h:6541
i
int i
Definition: gmock-matchers_test.cc:764
called_
bool called_
Definition: command_line_interface_unittest.cc:237
parameter_
std::string parameter_
Definition: command_line_interface_unittest.cc:238
GOOGLE_PROTOBUF_VERSION_SUFFIX
#define GOOGLE_PROTOBUF_VERSION_SUFFIX
Definition: common.h:87
FileDescriptorSet::file_size
int file_size() const
Definition: descriptor.pb.h:6535
EXPECT_PRED_FORMAT2
#define EXPECT_PRED_FORMAT2(pred_format, v1, v2)
Definition: gtest_pred_impl.h:163
return_code_
int return_code_
Definition: command_line_interface_unittest.cc:218
google::protobuf::StringReplace
void StringReplace(const string &s, const string &oldsub, const string &newsub, bool replace_all, string *res)
Definition: strutil.cc:148
google::protobuf::SplitStringUsing
void SplitStringUsing(const string &full, const char *delim, std::vector< string > *result)
Definition: strutil.cc:229
command_line_interface.h
duped_stdin_
int duped_stdin_
Definition: command_line_interface_unittest.cc:2364
googletest-break-on-failure-unittest.Run
def Run(command)
Definition: googletest-break-on-failure-unittest.py:76
google::protobuf::compiler::MockCodeGenerator::GetOutputFileName
static std::string GetOutputFileName(const std::string &generator_name, const FileDescriptor *file)
Definition: mock_code_generator.cc:297
google::protobuf::TEST_F
TEST_F(DynamicMessageTest, Descriptor)
Definition: dynamic_message_unittest.cc:126
GOOGLE_CHECK_OK
#define GOOGLE_CHECK_OK(A)
Definition: logging.h:155
google::protobuf::File::RecursivelyCreateDir
static bool RecursivelyCreateDir(const string &path, int mode)
Definition: file.cc:130
googletest.h
EXPECT_FALSE
#define EXPECT_FALSE(cond)
Definition: glog/src/googletest.h:145
google::protobuf::compiler::CommandLineInterface::AllowPlugins
void AllowPlugins(const std::string &exe_name_prefix)
Definition: command_line_interface.cc:819
unittest_proto_descriptor_set_filename_
std::string unittest_proto_descriptor_set_filename_
Definition: command_line_interface_unittest.cc:2367
stringprintf.h
testing::IsSubstring
GTEST_API_ AssertionResult IsSubstring(const char *needle_expr, const char *haystack_expr, const char *needle, const char *haystack)
Definition: gtest.cc:1624
DescriptorProto
Definition: descriptor.pb.h:1203
google::protobuf::Split
std::vector< string > Split(const string &full, const char *delim, bool skip_empty=true)
Definition: strutil.h:235
google::protobuf::File::ChangeWorkingDirectory
static bool ChangeWorkingDirectory(const string &new_working_directory)
Definition: file.cc:207
descriptor.h
FileDescriptorSet::descriptor
static const ::PROTOBUF_NAMESPACE_ID::Descriptor * descriptor()
Definition: descriptor.pb.h:371
substitute.h
io_win32.h
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: glcorearb.h:2879
file.h
google::protobuf::python::repeated_composite_container::Insert
static PyObject * Insert(PyObject *pself, PyObject *args)
Definition: repeated_composite_container.cc:139
GOOGLE_PROTOBUF_VERSION
#define GOOGLE_PROTOBUF_VERSION
Definition: common.h:84
google::protobuf::compiler::CommandLineInterface::kPathSeparator
static const char *const kPathSeparator
Definition: command_line_interface.h:111
descriptor.pb.h
google::protobuf::TestTempDir
string TestTempDir()
Definition: googletest.cc:189
google::protobuf::File::CreateDir
static bool CreateDir(const string &name, int mode)
Definition: file.cc:123
google::protobuf::TestUtil::TestSourceDir
std::string TestSourceDir()
Definition: test_util2.h:62
cli_
CommandLineInterface cli_
Definition: command_line_interface_unittest.cc:206
testing::Values
internal::ValueArray< T... > Values(T... v)
Definition: gtest-param-test.h:340
google::protobuf::compiler::MockCodeGenerator::CheckGeneratedAnnotations
static void CheckGeneratedAnnotations(const std::string &name, const std::string &file, const std::string &output_directory)
Definition: mock_code_generator.cc:151
compiler
Definition: plugin.pb.cc:22
google
Definition: data_proto2_to_proto3_util.h:11
message
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: glcorearb.h:2695
google::protobuf::File::DeleteRecursively
static void DeleteRecursively(const string &name, void *dummy1, void *dummy2)
Definition: file.cc:146
benchmarks.python.py_benchmark.args
args
Definition: py_benchmark.py:24
google::protobuf::File::Exists
static bool Exists(const string &name)
Definition: file.cc:69


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:48