PageRenderTime 82ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/protobuf/src/google/protobuf/compiler/command_line_interface_unittest.cc

http://decs.googlecode.com/
C++ | 1363 lines | 899 code | 307 blank | 157 comment | 26 complexity | 972e7253aed087d2d0f2c37a2c62d752 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // http://code.google.com/p/protobuf/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Author: kenton@google.com (Kenton Varda)
  31. // Based on original Protocol Buffers design by
  32. // Sanjay Ghemawat, Jeff Dean, and others.
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #include <fcntl.h>
  36. #ifdef _MSC_VER
  37. #include <io.h>
  38. #else
  39. #include <unistd.h>
  40. #endif
  41. #include <vector>
  42. #include <google/protobuf/descriptor.pb.h>
  43. #include <google/protobuf/descriptor.h>
  44. #include <google/protobuf/io/zero_copy_stream.h>
  45. #include <google/protobuf/compiler/command_line_interface.h>
  46. #include <google/protobuf/compiler/code_generator.h>
  47. #include <google/protobuf/io/printer.h>
  48. #include <google/protobuf/unittest.pb.h>
  49. #include <google/protobuf/testing/file.h>
  50. #include <google/protobuf/stubs/strutil.h>
  51. #include <google/protobuf/testing/googletest.h>
  52. #include <gtest/gtest.h>
  53. namespace google {
  54. namespace protobuf {
  55. namespace compiler {
  56. #if defined(_WIN32)
  57. #ifndef STDIN_FILENO
  58. #define STDIN_FILENO 0
  59. #endif
  60. #ifndef STDOUT_FILENO
  61. #define STDOUT_FILENO 1
  62. #endif
  63. #endif
  64. namespace {
  65. class CommandLineInterfaceTest : public testing::Test {
  66. protected:
  67. virtual void SetUp();
  68. virtual void TearDown();
  69. // Runs the CommandLineInterface with the given command line. The
  70. // command is automatically split on spaces, and the string "$tmpdir"
  71. // is replaced with TestTempDir().
  72. void Run(const string& command);
  73. // -----------------------------------------------------------------
  74. // Methods to set up the test (called before Run()).
  75. class MockCodeGenerator;
  76. class NullCodeGenerator;
  77. // Registers a MockCodeGenerator with the given name.
  78. MockCodeGenerator* RegisterGenerator(const string& generator_name,
  79. const string& flag_name,
  80. const string& filename,
  81. const string& help_text);
  82. MockCodeGenerator* RegisterErrorGenerator(const string& generator_name,
  83. const string& error_text,
  84. const string& flag_name,
  85. const string& filename,
  86. const string& help_text);
  87. // Registers a CodeGenerator which will not actually generate anything,
  88. // but records the parameter passed to the generator.
  89. NullCodeGenerator* RegisterNullGenerator(const string& flag_name);
  90. // Create a temp file within temp_directory_ with the given name.
  91. // The containing directory is also created if necessary.
  92. void CreateTempFile(const string& name, const string& contents);
  93. void SetInputsAreProtoPathRelative(bool enable) {
  94. cli_.SetInputsAreProtoPathRelative(enable);
  95. }
  96. // -----------------------------------------------------------------
  97. // Methods to check the test results (called after Run()).
  98. // Checks that no text was written to stderr during Run(), and Run()
  99. // returned 0.
  100. void ExpectNoErrors();
  101. // Checks that Run() returned non-zero and the stderr output is exactly
  102. // the text given. expected_test may contain references to "$tmpdir",
  103. // which will be replaced by the temporary directory path.
  104. void ExpectErrorText(const string& expected_text);
  105. // Checks that Run() returned non-zero and the stderr contains the given
  106. // substring.
  107. void ExpectErrorSubstring(const string& expected_substring);
  108. // Returns true if ExpectErrorSubstring(expected_substring) would pass, but
  109. // does not fail otherwise.
  110. bool HasAlternateErrorSubstring(const string& expected_substring);
  111. // Checks that MockCodeGenerator::Generate() was called in the given
  112. // context. That is, this tests if the generator with the given name
  113. // was called with the given parameter and proto file and produced the
  114. // given output file. This is checked by reading the output file and
  115. // checking that it contains the content that MockCodeGenerator would
  116. // generate given these inputs. message_name is the name of the first
  117. // message that appeared in the proto file; this is just to make extra
  118. // sure that the correct file was parsed.
  119. void ExpectGenerated(const string& generator_name,
  120. const string& parameter,
  121. const string& proto_name,
  122. const string& message_name,
  123. const string& output_file);
  124. void ReadDescriptorSet(const string& filename,
  125. FileDescriptorSet* descriptor_set);
  126. private:
  127. // The object we are testing.
  128. CommandLineInterface cli_;
  129. // We create a directory within TestTempDir() in order to add extra
  130. // protection against accidentally deleting user files (since we recursively
  131. // delete this directory during the test). This is the full path of that
  132. // directory.
  133. string temp_directory_;
  134. // The result of Run().
  135. int return_code_;
  136. // The captured stderr output.
  137. string error_text_;
  138. // Pointers which need to be deleted later.
  139. vector<CodeGenerator*> mock_generators_to_delete_;
  140. };
  141. // A mock CodeGenerator which outputs information about the context in which
  142. // it was called, which can then be checked. Output is written to a filename
  143. // constructed by concatenating the filename_prefix (given to the constructor)
  144. // with the proto file name, separated by a '.'.
  145. class CommandLineInterfaceTest::MockCodeGenerator : public CodeGenerator {
  146. public:
  147. // Create a MockCodeGenerator whose Generate() method returns true.
  148. MockCodeGenerator(const string& name, const string& filename_prefix);
  149. // Create a MockCodeGenerator whose Generate() method returns false
  150. // and sets the error string to the given string.
  151. MockCodeGenerator(const string& name, const string& filename_prefix,
  152. const string& error);
  153. ~MockCodeGenerator();
  154. void set_expect_write_error(bool value) {
  155. expect_write_error_ = value;
  156. }
  157. // implements CodeGenerator ----------------------------------------
  158. bool Generate(const FileDescriptor* file,
  159. const string& parameter,
  160. OutputDirectory* output_directory,
  161. string* error) const;
  162. private:
  163. string name_;
  164. string filename_prefix_;
  165. bool return_error_;
  166. string error_;
  167. bool expect_write_error_;
  168. };
  169. class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator {
  170. public:
  171. NullCodeGenerator() : called_(false) {}
  172. ~NullCodeGenerator() {}
  173. mutable bool called_;
  174. mutable string parameter_;
  175. // implements CodeGenerator ----------------------------------------
  176. bool Generate(const FileDescriptor* file,
  177. const string& parameter,
  178. OutputDirectory* output_directory,
  179. string* error) const {
  180. called_ = true;
  181. parameter_ = parameter;
  182. return true;
  183. }
  184. };
  185. // ===================================================================
  186. void CommandLineInterfaceTest::SetUp() {
  187. // Most of these tests were written before this option was added, so we
  188. // run with the option on (which used to be the only way) except in certain
  189. // tests where we turn it off.
  190. cli_.SetInputsAreProtoPathRelative(true);
  191. temp_directory_ = TestTempDir() + "/proto2_cli_test_temp";
  192. // If the temp directory already exists, it must be left over from a
  193. // previous run. Delete it.
  194. if (File::Exists(temp_directory_)) {
  195. File::DeleteRecursively(temp_directory_, NULL, NULL);
  196. }
  197. // Create the temp directory.
  198. GOOGLE_CHECK(File::CreateDir(temp_directory_.c_str(), DEFAULT_FILE_MODE));
  199. }
  200. void CommandLineInterfaceTest::TearDown() {
  201. // Delete the temp directory.
  202. File::DeleteRecursively(temp_directory_, NULL, NULL);
  203. // Delete all the MockCodeGenerators.
  204. for (int i = 0; i < mock_generators_to_delete_.size(); i++) {
  205. delete mock_generators_to_delete_[i];
  206. }
  207. mock_generators_to_delete_.clear();
  208. }
  209. void CommandLineInterfaceTest::Run(const string& command) {
  210. vector<string> args;
  211. SplitStringUsing(command, " ", &args);
  212. scoped_array<const char*> argv(new const char*[args.size()]);
  213. for (int i = 0; i < args.size(); i++) {
  214. args[i] = StringReplace(args[i], "$tmpdir", temp_directory_, true);
  215. argv[i] = args[i].c_str();
  216. }
  217. CaptureTestStderr();
  218. return_code_ = cli_.Run(args.size(), argv.get());
  219. error_text_ = GetCapturedTestStderr();
  220. }
  221. // -------------------------------------------------------------------
  222. CommandLineInterfaceTest::MockCodeGenerator*
  223. CommandLineInterfaceTest::RegisterGenerator(
  224. const string& generator_name,
  225. const string& flag_name,
  226. const string& filename,
  227. const string& help_text) {
  228. MockCodeGenerator* generator =
  229. new MockCodeGenerator(generator_name, filename);
  230. mock_generators_to_delete_.push_back(generator);
  231. cli_.RegisterGenerator(flag_name, generator, help_text);
  232. return generator;
  233. }
  234. CommandLineInterfaceTest::MockCodeGenerator*
  235. CommandLineInterfaceTest::RegisterErrorGenerator(
  236. const string& generator_name,
  237. const string& error_text,
  238. const string& flag_name,
  239. const string& filename_prefix,
  240. const string& help_text) {
  241. MockCodeGenerator* generator =
  242. new MockCodeGenerator(generator_name, filename_prefix, error_text);
  243. mock_generators_to_delete_.push_back(generator);
  244. cli_.RegisterGenerator(flag_name, generator, help_text);
  245. return generator;
  246. }
  247. CommandLineInterfaceTest::NullCodeGenerator*
  248. CommandLineInterfaceTest::RegisterNullGenerator(
  249. const string& flag_name) {
  250. NullCodeGenerator* generator = new NullCodeGenerator;
  251. mock_generators_to_delete_.push_back(generator);
  252. cli_.RegisterGenerator(flag_name, generator, "");
  253. return generator;
  254. }
  255. void CommandLineInterfaceTest::CreateTempFile(
  256. const string& name,
  257. const string& contents) {
  258. // Create parent directory, if necessary.
  259. string::size_type slash_pos = name.find_last_of('/');
  260. if (slash_pos != string::npos) {
  261. string dir = name.substr(0, slash_pos);
  262. File::RecursivelyCreateDir(temp_directory_ + "/" + dir, 0777);
  263. }
  264. // Write file.
  265. string full_name = temp_directory_ + "/" + name;
  266. File::WriteStringToFileOrDie(contents, full_name);
  267. }
  268. // -------------------------------------------------------------------
  269. void CommandLineInterfaceTest::ExpectNoErrors() {
  270. EXPECT_EQ(0, return_code_);
  271. EXPECT_EQ("", error_text_);
  272. }
  273. void CommandLineInterfaceTest::ExpectErrorText(const string& expected_text) {
  274. EXPECT_NE(0, return_code_);
  275. EXPECT_EQ(StringReplace(expected_text, "$tmpdir", temp_directory_, true),
  276. error_text_);
  277. }
  278. void CommandLineInterfaceTest::ExpectErrorSubstring(
  279. const string& expected_substring) {
  280. EXPECT_NE(0, return_code_);
  281. EXPECT_PRED_FORMAT2(testing::IsSubstring, expected_substring, error_text_);
  282. }
  283. bool CommandLineInterfaceTest::HasAlternateErrorSubstring(
  284. const string& expected_substring) {
  285. EXPECT_NE(0, return_code_);
  286. return error_text_.find(expected_substring) != string::npos;
  287. }
  288. void CommandLineInterfaceTest::ExpectGenerated(
  289. const string& generator_name,
  290. const string& parameter,
  291. const string& proto_name,
  292. const string& message_name,
  293. const string& output_file_prefix) {
  294. // Open and read the file.
  295. string output_file = output_file_prefix + "." + proto_name;
  296. string file_contents;
  297. ASSERT_TRUE(File::ReadFileToString(temp_directory_ + "/" + output_file,
  298. &file_contents))
  299. << "Failed to open file: " + output_file;
  300. // Check that the contents are as we expect.
  301. string expected_contents =
  302. generator_name + ": " + parameter + ", " + proto_name + ", " +
  303. message_name + "\n";
  304. EXPECT_EQ(expected_contents, file_contents)
  305. << "Output file did not have expected contents: " + output_file;
  306. }
  307. void CommandLineInterfaceTest::ReadDescriptorSet(
  308. const string& filename, FileDescriptorSet* descriptor_set) {
  309. string path = temp_directory_ + "/" + filename;
  310. string file_contents;
  311. if (!File::ReadFileToString(path, &file_contents)) {
  312. FAIL() << "File not found: " << path;
  313. }
  314. if (!descriptor_set->ParseFromString(file_contents)) {
  315. FAIL() << "Could not parse file contents: " << path;
  316. }
  317. }
  318. // ===================================================================
  319. CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator(
  320. const string& name, const string& filename_prefix)
  321. : name_(name),
  322. filename_prefix_(filename_prefix),
  323. return_error_(false),
  324. expect_write_error_(false) {
  325. }
  326. CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator(
  327. const string& name, const string& filename_prefix, const string& error)
  328. : name_(name),
  329. filename_prefix_(filename_prefix),
  330. return_error_(true),
  331. error_(error),
  332. expect_write_error_(false) {
  333. }
  334. CommandLineInterfaceTest::MockCodeGenerator::~MockCodeGenerator() {}
  335. bool CommandLineInterfaceTest::MockCodeGenerator::Generate(
  336. const FileDescriptor* file,
  337. const string& parameter,
  338. OutputDirectory* output_directory,
  339. string* error) const {
  340. scoped_ptr<io::ZeroCopyOutputStream> output(
  341. output_directory->Open(filename_prefix_ + "." + file->name()));
  342. io::Printer printer(output.get(), '$');
  343. map<string, string> vars;
  344. vars["name"] = name_;
  345. vars["parameter"] = parameter;
  346. vars["proto_name"] = file->name();
  347. vars["message_name"] = file->message_type_count() > 0 ?
  348. file->message_type(0)->full_name().c_str() : "(none)";
  349. printer.Print(vars, "$name$: $parameter$, $proto_name$, $message_name$\n");
  350. if (expect_write_error_) {
  351. EXPECT_TRUE(printer.failed());
  352. } else {
  353. EXPECT_FALSE(printer.failed());
  354. }
  355. *error = error_;
  356. return !return_error_;
  357. }
  358. // ===================================================================
  359. TEST_F(CommandLineInterfaceTest, BasicOutput) {
  360. // Test that the common case works.
  361. RegisterGenerator("test_generator", "--test_out",
  362. "output.test", "Test output.");
  363. CreateTempFile("foo.proto",
  364. "syntax = \"proto2\";\n"
  365. "message Foo {}\n");
  366. Run("protocol_compiler --test_out=$tmpdir "
  367. "--proto_path=$tmpdir foo.proto");
  368. ExpectNoErrors();
  369. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  370. }
  371. TEST_F(CommandLineInterfaceTest, MultipleInputs) {
  372. // Test parsing multiple input files.
  373. RegisterGenerator("test_generator", "--test_out",
  374. "output.test", "Test output.");
  375. CreateTempFile("foo.proto",
  376. "syntax = \"proto2\";\n"
  377. "message Foo {}\n");
  378. CreateTempFile("bar.proto",
  379. "syntax = \"proto2\";\n"
  380. "message Bar {}\n");
  381. Run("protocol_compiler --test_out=$tmpdir "
  382. "--proto_path=$tmpdir foo.proto bar.proto");
  383. ExpectNoErrors();
  384. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  385. ExpectGenerated("test_generator", "", "bar.proto", "Bar", "output.test");
  386. }
  387. TEST_F(CommandLineInterfaceTest, CreateDirectory) {
  388. // Test that when we output to a sub-directory, it is created.
  389. RegisterGenerator("test_generator", "--test_out",
  390. "bar/baz/output.test", "Test output.");
  391. CreateTempFile("foo.proto",
  392. "syntax = \"proto2\";\n"
  393. "message Foo {}\n");
  394. Run("protocol_compiler --test_out=$tmpdir "
  395. "--proto_path=$tmpdir foo.proto");
  396. ExpectNoErrors();
  397. ExpectGenerated("test_generator", "",
  398. "foo.proto", "Foo", "bar/baz/output.test");
  399. }
  400. TEST_F(CommandLineInterfaceTest, GeneratorParameters) {
  401. // Test that generator parameters are correctly parsed from the command line.
  402. RegisterGenerator("test_generator", "--test_out",
  403. "output.test", "Test output.");
  404. CreateTempFile("foo.proto",
  405. "syntax = \"proto2\";\n"
  406. "message Foo {}\n");
  407. Run("protocol_compiler --test_out=TestParameter:$tmpdir "
  408. "--proto_path=$tmpdir foo.proto");
  409. ExpectNoErrors();
  410. ExpectGenerated("test_generator", "TestParameter",
  411. "foo.proto", "Foo", "output.test");
  412. }
  413. #if defined(_WIN32) || defined(__CYGWIN__)
  414. TEST_F(CommandLineInterfaceTest, WindowsOutputPath) {
  415. // Test that the output path can be a Windows-style path.
  416. NullCodeGenerator* generator = RegisterNullGenerator("--test_out");
  417. CreateTempFile("foo.proto",
  418. "syntax = \"proto2\";\n");
  419. Run("protocol_compiler --test_out=C:\\ "
  420. "--proto_path=$tmpdir foo.proto");
  421. ExpectNoErrors();
  422. EXPECT_TRUE(generator->called_);
  423. EXPECT_EQ("", generator->parameter_);
  424. }
  425. TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) {
  426. // Test that we can have a windows-style output path and a parameter.
  427. NullCodeGenerator* generator = RegisterNullGenerator("--test_out");
  428. CreateTempFile("foo.proto",
  429. "syntax = \"proto2\";\n");
  430. Run("protocol_compiler --test_out=bar:C:\\ "
  431. "--proto_path=$tmpdir foo.proto");
  432. ExpectNoErrors();
  433. EXPECT_TRUE(generator->called_);
  434. EXPECT_EQ("bar", generator->parameter_);
  435. }
  436. TEST_F(CommandLineInterfaceTest, TrailingBackslash) {
  437. // Test that the directories can end in backslashes. Some users claim this
  438. // doesn't work on their system.
  439. RegisterGenerator("test_generator", "--test_out",
  440. "output.test", "Test output.");
  441. CreateTempFile("foo.proto",
  442. "syntax = \"proto2\";\n"
  443. "message Foo {}\n");
  444. Run("protocol_compiler --test_out=$tmpdir\\ "
  445. "--proto_path=$tmpdir\\ foo.proto");
  446. ExpectNoErrors();
  447. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  448. }
  449. #endif // defined(_WIN32) || defined(__CYGWIN__)
  450. TEST_F(CommandLineInterfaceTest, PathLookup) {
  451. // Test that specifying multiple directories in the proto search path works.
  452. RegisterGenerator("test_generator", "--test_out",
  453. "output.test", "Test output.");
  454. CreateTempFile("b/bar.proto",
  455. "syntax = \"proto2\";\n"
  456. "message Bar {}\n");
  457. CreateTempFile("a/foo.proto",
  458. "syntax = \"proto2\";\n"
  459. "import \"bar.proto\";\n"
  460. "message Foo {\n"
  461. " optional Bar a = 1;\n"
  462. "}\n");
  463. CreateTempFile("b/foo.proto", "this should not be parsed\n");
  464. Run("protocol_compiler --test_out=$tmpdir "
  465. "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto");
  466. ExpectNoErrors();
  467. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  468. }
  469. TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) {
  470. // Same as PathLookup, but we provide the proto_path in a single flag.
  471. RegisterGenerator("test_generator", "--test_out",
  472. "output.test", "Test output.");
  473. CreateTempFile("b/bar.proto",
  474. "syntax = \"proto2\";\n"
  475. "message Bar {}\n");
  476. CreateTempFile("a/foo.proto",
  477. "syntax = \"proto2\";\n"
  478. "import \"bar.proto\";\n"
  479. "message Foo {\n"
  480. " optional Bar a = 1;\n"
  481. "}\n");
  482. CreateTempFile("b/foo.proto", "this should not be parsed\n");
  483. #undef PATH_SEPARATOR
  484. #if defined(_WIN32)
  485. #define PATH_SEPARATOR ";"
  486. #else
  487. #define PATH_SEPARATOR ":"
  488. #endif
  489. Run("protocol_compiler --test_out=$tmpdir "
  490. "--proto_path=$tmpdir/a"PATH_SEPARATOR"$tmpdir/b foo.proto");
  491. #undef PATH_SEPARATOR
  492. ExpectNoErrors();
  493. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  494. }
  495. TEST_F(CommandLineInterfaceTest, NonRootMapping) {
  496. // Test setting up a search path mapping a directory to a non-root location.
  497. RegisterGenerator("test_generator", "--test_out",
  498. "output.test", "Test output.");
  499. CreateTempFile("foo.proto",
  500. "syntax = \"proto2\";\n"
  501. "message Foo {}\n");
  502. Run("protocol_compiler --test_out=$tmpdir "
  503. "--proto_path=bar=$tmpdir bar/foo.proto");
  504. ExpectNoErrors();
  505. ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo", "output.test");
  506. }
  507. TEST_F(CommandLineInterfaceTest, MultipleGenerators) {
  508. // Test that we can have multiple generators and use both in one invocation,
  509. // each with a different output directory.
  510. RegisterGenerator("test_generator_1", "--test1_out",
  511. "output1.test", "Test output 1.");
  512. RegisterGenerator("test_generator_2", "--test2_out",
  513. "output2.test", "Test output 2.");
  514. CreateTempFile("foo.proto",
  515. "syntax = \"proto2\";\n"
  516. "message Foo {}\n");
  517. // Create the "a" and "b" sub-directories.
  518. CreateTempFile("a/dummy", "");
  519. CreateTempFile("b/dummy", "");
  520. Run("protocol_compiler "
  521. "--test1_out=$tmpdir/a "
  522. "--test2_out=$tmpdir/b "
  523. "--proto_path=$tmpdir foo.proto");
  524. ExpectNoErrors();
  525. ExpectGenerated("test_generator_1", "", "foo.proto", "Foo", "a/output1.test");
  526. ExpectGenerated("test_generator_2", "", "foo.proto", "Foo", "b/output2.test");
  527. }
  528. TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) {
  529. // Test that --disallow_services doesn't cause a problem when there are no
  530. // services.
  531. RegisterGenerator("test_generator", "--test_out",
  532. "output.test", "Test output.");
  533. CreateTempFile("foo.proto",
  534. "syntax = \"proto2\";\n"
  535. "message Foo {}\n");
  536. Run("protocol_compiler --disallow_services --test_out=$tmpdir "
  537. "--proto_path=$tmpdir foo.proto");
  538. ExpectNoErrors();
  539. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  540. }
  541. TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) {
  542. // Test that --disallow_services produces an error when there are services.
  543. RegisterGenerator("test_generator", "--test_out",
  544. "output.test", "Test output.");
  545. CreateTempFile("foo.proto",
  546. "syntax = \"proto2\";\n"
  547. "message Foo {}\n"
  548. "service Bar {}\n");
  549. Run("protocol_compiler --disallow_services --test_out=$tmpdir "
  550. "--proto_path=$tmpdir foo.proto");
  551. ExpectErrorSubstring("foo.proto: This file contains services");
  552. }
  553. TEST_F(CommandLineInterfaceTest, AllowServicesHasService) {
  554. // Test that services work fine as long as --disallow_services is not used.
  555. RegisterGenerator("test_generator", "--test_out",
  556. "output.test", "Test output.");
  557. CreateTempFile("foo.proto",
  558. "syntax = \"proto2\";\n"
  559. "message Foo {}\n"
  560. "service Bar {}\n");
  561. Run("protocol_compiler --test_out=$tmpdir "
  562. "--proto_path=$tmpdir foo.proto");
  563. ExpectNoErrors();
  564. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  565. }
  566. TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) {
  567. // Test that we can accept working-directory-relative input files.
  568. SetInputsAreProtoPathRelative(false);
  569. RegisterGenerator("test_generator", "--test_out",
  570. "output.test", "Test output.");
  571. CreateTempFile("foo.proto",
  572. "syntax = \"proto2\";\n"
  573. "message Foo {}\n");
  574. Run("protocol_compiler --test_out=$tmpdir "
  575. "--proto_path=$tmpdir $tmpdir/foo.proto");
  576. ExpectNoErrors();
  577. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  578. }
  579. TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) {
  580. CreateTempFile("foo.proto",
  581. "syntax = \"proto2\";\n"
  582. "message Foo {}\n");
  583. CreateTempFile("bar.proto",
  584. "syntax = \"proto2\";\n"
  585. "import \"foo.proto\";\n"
  586. "message Bar {\n"
  587. " optional Foo foo = 1;\n"
  588. "}\n");
  589. Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
  590. "--proto_path=$tmpdir bar.proto");
  591. ExpectNoErrors();
  592. FileDescriptorSet descriptor_set;
  593. ReadDescriptorSet("descriptor_set", &descriptor_set);
  594. if (HasFatalFailure()) return;
  595. ASSERT_EQ(1, descriptor_set.file_size());
  596. EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
  597. }
  598. TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) {
  599. CreateTempFile("foo.proto",
  600. "syntax = \"proto2\";\n"
  601. "message Foo {}\n");
  602. CreateTempFile("bar.proto",
  603. "syntax = \"proto2\";\n"
  604. "import \"foo.proto\";\n"
  605. "message Bar {\n"
  606. " optional Foo foo = 1;\n"
  607. "}\n");
  608. Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
  609. "--include_imports --proto_path=$tmpdir bar.proto");
  610. ExpectNoErrors();
  611. FileDescriptorSet descriptor_set;
  612. ReadDescriptorSet("descriptor_set", &descriptor_set);
  613. if (HasFatalFailure()) return;
  614. ASSERT_EQ(2, descriptor_set.file_size());
  615. if (descriptor_set.file(0).name() == "bar.proto") {
  616. swap(descriptor_set.mutable_file()->mutable_data()[0],
  617. descriptor_set.mutable_file()->mutable_data()[1]);
  618. }
  619. EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
  620. EXPECT_EQ("bar.proto", descriptor_set.file(1).name());
  621. }
  622. // -------------------------------------------------------------------
  623. TEST_F(CommandLineInterfaceTest, ParseErrors) {
  624. // Test that parse errors are reported.
  625. RegisterGenerator("test_generator", "--test_out",
  626. "output.test", "Test output.");
  627. CreateTempFile("foo.proto",
  628. "syntax = \"proto2\";\n"
  629. "badsyntax\n");
  630. Run("protocol_compiler --test_out=$tmpdir "
  631. "--proto_path=$tmpdir foo.proto");
  632. ExpectErrorText(
  633. "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n");
  634. }
  635. TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) {
  636. // Test that parse errors are reported from multiple files.
  637. RegisterGenerator("test_generator", "--test_out",
  638. "output.test", "Test output.");
  639. // We set up files such that foo.proto actually depends on bar.proto in
  640. // two ways: Directly and through baz.proto. bar.proto's errors should
  641. // only be reported once.
  642. CreateTempFile("bar.proto",
  643. "syntax = \"proto2\";\n"
  644. "badsyntax\n");
  645. CreateTempFile("baz.proto",
  646. "syntax = \"proto2\";\n"
  647. "import \"bar.proto\";\n");
  648. CreateTempFile("foo.proto",
  649. "syntax = \"proto2\";\n"
  650. "import \"bar.proto\";\n"
  651. "import \"baz.proto\";\n");
  652. Run("protocol_compiler --test_out=$tmpdir "
  653. "--proto_path=$tmpdir foo.proto");
  654. ExpectErrorText(
  655. "bar.proto:2:1: Expected top-level statement (e.g. \"message\").\n"
  656. "baz.proto: Import \"bar.proto\" was not found or had errors.\n"
  657. "foo.proto: Import \"bar.proto\" was not found or had errors.\n"
  658. "foo.proto: Import \"baz.proto\" was not found or had errors.\n");
  659. }
  660. TEST_F(CommandLineInterfaceTest, InputNotFoundError) {
  661. // Test what happens if the input file is not found.
  662. RegisterGenerator("test_generator", "--test_out",
  663. "output.test", "Test output.");
  664. Run("protocol_compiler --test_out=$tmpdir "
  665. "--proto_path=$tmpdir foo.proto");
  666. ExpectErrorText(
  667. "foo.proto: File not found.\n");
  668. }
  669. TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) {
  670. // Test what happens when a working-directory-relative input file is not
  671. // found.
  672. SetInputsAreProtoPathRelative(false);
  673. RegisterGenerator("test_generator", "--test_out",
  674. "output.test", "Test output.");
  675. Run("protocol_compiler --test_out=$tmpdir "
  676. "--proto_path=$tmpdir $tmpdir/foo.proto");
  677. ExpectErrorText(
  678. "$tmpdir/foo.proto: No such file or directory\n");
  679. }
  680. TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) {
  681. // Test what happens when a working-directory-relative input file is not
  682. // mapped to a virtual path.
  683. SetInputsAreProtoPathRelative(false);
  684. RegisterGenerator("test_generator", "--test_out",
  685. "output.test", "Test output.");
  686. CreateTempFile("foo.proto",
  687. "syntax = \"proto2\";\n"
  688. "message Foo {}\n");
  689. // Create a directory called "bar" so that we can point --proto_path at it.
  690. CreateTempFile("bar/dummy", "");
  691. Run("protocol_compiler --test_out=$tmpdir "
  692. "--proto_path=$tmpdir/bar $tmpdir/foo.proto");
  693. ExpectErrorText(
  694. "$tmpdir/foo.proto: File does not reside within any path "
  695. "specified using --proto_path (or -I). You must specify a "
  696. "--proto_path which encompasses this file.\n");
  697. }
  698. TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) {
  699. // Check what happens if the input file is not found *and* is not mapped
  700. // in the proto_path.
  701. SetInputsAreProtoPathRelative(false);
  702. RegisterGenerator("test_generator", "--test_out",
  703. "output.test", "Test output.");
  704. // Create a directory called "bar" so that we can point --proto_path at it.
  705. CreateTempFile("bar/dummy", "");
  706. Run("protocol_compiler --test_out=$tmpdir "
  707. "--proto_path=$tmpdir/bar $tmpdir/foo.proto");
  708. ExpectErrorText(
  709. "$tmpdir/foo.proto: No such file or directory\n");
  710. }
  711. TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) {
  712. // Test what happens when a working-directory-relative input file is shadowed
  713. // by another file in the virtual path.
  714. SetInputsAreProtoPathRelative(false);
  715. RegisterGenerator("test_generator", "--test_out",
  716. "output.test", "Test output.");
  717. CreateTempFile("foo/foo.proto",
  718. "syntax = \"proto2\";\n"
  719. "message Foo {}\n");
  720. CreateTempFile("bar/foo.proto",
  721. "syntax = \"proto2\";\n"
  722. "message Bar {}\n");
  723. Run("protocol_compiler --test_out=$tmpdir "
  724. "--proto_path=$tmpdir/foo --proto_path=$tmpdir/bar "
  725. "$tmpdir/bar/foo.proto");
  726. ExpectErrorText(
  727. "$tmpdir/bar/foo.proto: Input is shadowed in the --proto_path "
  728. "by \"$tmpdir/foo/foo.proto\". Either use the latter "
  729. "file as your input or reorder the --proto_path so that the "
  730. "former file's location comes first.\n");
  731. }
  732. TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) {
  733. // Test what happens if the input file is not found.
  734. RegisterGenerator("test_generator", "--test_out",
  735. "output.test", "Test output.");
  736. Run("protocol_compiler --test_out=$tmpdir "
  737. "--proto_path=$tmpdir/foo foo.proto");
  738. ExpectErrorText(
  739. "$tmpdir/foo: warning: directory does not exist.\n"
  740. "foo.proto: File not found.\n");
  741. }
  742. TEST_F(CommandLineInterfaceTest, MissingInputError) {
  743. // Test that we get an error if no inputs are given.
  744. RegisterGenerator("test_generator", "--test_out",
  745. "output.test", "Test output.");
  746. Run("protocol_compiler --test_out=$tmpdir "
  747. "--proto_path=$tmpdir");
  748. ExpectErrorText("Missing input file.\n");
  749. }
  750. TEST_F(CommandLineInterfaceTest, MissingOutputError) {
  751. RegisterGenerator("test_generator", "--test_out",
  752. "output.test", "Test output.");
  753. CreateTempFile("foo.proto",
  754. "syntax = \"proto2\";\n"
  755. "message Foo {}\n");
  756. Run("protocol_compiler --proto_path=$tmpdir foo.proto");
  757. ExpectErrorText("Missing output directives.\n");
  758. }
  759. TEST_F(CommandLineInterfaceTest, OutputWriteError) {
  760. MockCodeGenerator* generator =
  761. RegisterGenerator("test_generator", "--test_out",
  762. "output.test", "Test output.");
  763. generator->set_expect_write_error(true);
  764. CreateTempFile("foo.proto",
  765. "syntax = \"proto2\";\n"
  766. "message Foo {}\n");
  767. // Create a directory blocking our output location.
  768. CreateTempFile("output.test.foo.proto/foo", "");
  769. Run("protocol_compiler --test_out=$tmpdir "
  770. "--proto_path=$tmpdir foo.proto");
  771. #if defined(_WIN32) && !defined(__CYGWIN__)
  772. // Windows with MSVCRT.dll produces EPERM instead of EISDIR.
  773. if (HasAlternateErrorSubstring("output.test.foo.proto: Permission denied")) {
  774. return;
  775. }
  776. #endif
  777. ExpectErrorSubstring("output.test.foo.proto: Is a directory");
  778. }
  779. TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) {
  780. RegisterGenerator("test_generator", "--test_out",
  781. "output.test", "Test output.");
  782. CreateTempFile("foo.proto",
  783. "syntax = \"proto2\";\n"
  784. "message Foo {}\n");
  785. Run("protocol_compiler --test_out=$tmpdir/nosuchdir "
  786. "--proto_path=$tmpdir foo.proto");
  787. ExpectErrorSubstring("nosuchdir/: "
  788. "No such file or directory");
  789. }
  790. TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) {
  791. RegisterGenerator("test_generator", "--test_out",
  792. "output.test", "Test output.");
  793. CreateTempFile("foo.proto",
  794. "syntax = \"proto2\";\n"
  795. "message Foo {}\n");
  796. Run("protocol_compiler --test_out=$tmpdir/foo.proto "
  797. "--proto_path=$tmpdir foo.proto");
  798. #if defined(_WIN32) && !defined(__CYGWIN__)
  799. // Windows with MSVCRT.dll produces EINVAL instead of ENOTDIR.
  800. if (HasAlternateErrorSubstring("foo.proto/: Invalid argument")) {
  801. return;
  802. }
  803. #endif
  804. ExpectErrorSubstring("foo.proto/: Not a directory");
  805. }
  806. TEST_F(CommandLineInterfaceTest, GeneratorError) {
  807. RegisterErrorGenerator("error_generator", "Test error message.",
  808. "--error_out", "output.test", "Test error output.");
  809. CreateTempFile("foo.proto",
  810. "syntax = \"proto2\";\n"
  811. "message Foo {}\n");
  812. Run("protocol_compiler --error_out=$tmpdir "
  813. "--proto_path=$tmpdir foo.proto");
  814. ExpectErrorSubstring("--error_out: Test error message.");
  815. }
  816. TEST_F(CommandLineInterfaceTest, HelpText) {
  817. RegisterGenerator("test_generator", "--test_out",
  818. "output.test", "Test output.");
  819. RegisterErrorGenerator("error_generator", "Test error message.",
  820. "--error_out", "output.test", "Test error output.");
  821. CreateTempFile("foo.proto",
  822. "syntax = \"proto2\";\n"
  823. "message Foo {}\n");
  824. Run("test_exec_name --help");
  825. ExpectErrorSubstring("Usage: test_exec_name ");
  826. ExpectErrorSubstring("--test_out=OUT_DIR");
  827. ExpectErrorSubstring("Test output.");
  828. ExpectErrorSubstring("--error_out=OUT_DIR");
  829. ExpectErrorSubstring("Test error output.");
  830. }
  831. TEST_F(CommandLineInterfaceTest, GccFormatErrors) {
  832. // Test --error_format=gcc (which is the default, but we want to verify
  833. // that it can be set explicitly).
  834. RegisterGenerator("test_generator", "--test_out",
  835. "output.test", "Test output.");
  836. CreateTempFile("foo.proto",
  837. "syntax = \"proto2\";\n"
  838. "badsyntax\n");
  839. Run("protocol_compiler --test_out=$tmpdir "
  840. "--proto_path=$tmpdir --error_format=gcc foo.proto");
  841. ExpectErrorText(
  842. "foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n");
  843. }
  844. TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) {
  845. // Test --error_format=msvs
  846. RegisterGenerator("test_generator", "--test_out",
  847. "output.test", "Test output.");
  848. CreateTempFile("foo.proto",
  849. "syntax = \"proto2\";\n"
  850. "badsyntax\n");
  851. Run("protocol_compiler --test_out=$tmpdir "
  852. "--proto_path=$tmpdir --error_format=msvs foo.proto");
  853. ExpectErrorText(
  854. "foo.proto(2) : error in column=1: Expected top-level statement "
  855. "(e.g. \"message\").\n");
  856. }
  857. TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) {
  858. // Test --error_format=msvs
  859. RegisterGenerator("test_generator", "--test_out",
  860. "output.test", "Test output.");
  861. CreateTempFile("foo.proto",
  862. "syntax = \"proto2\";\n"
  863. "badsyntax\n");
  864. Run("protocol_compiler --test_out=$tmpdir "
  865. "--proto_path=$tmpdir --error_format=invalid foo.proto");
  866. ExpectErrorText(
  867. "Unknown error format: invalid\n");
  868. }
  869. // -------------------------------------------------------------------
  870. // Flag parsing tests
  871. TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) {
  872. // Test that a single-character flag works.
  873. RegisterGenerator("test_generator", "-t",
  874. "output.test", "Test output.");
  875. CreateTempFile("foo.proto",
  876. "syntax = \"proto2\";\n"
  877. "message Foo {}\n");
  878. Run("protocol_compiler -t$tmpdir "
  879. "--proto_path=$tmpdir foo.proto");
  880. ExpectNoErrors();
  881. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  882. }
  883. TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) {
  884. // Test that separating the flag value with a space works.
  885. RegisterGenerator("test_generator", "--test_out",
  886. "output.test", "Test output.");
  887. CreateTempFile("foo.proto",
  888. "syntax = \"proto2\";\n"
  889. "message Foo {}\n");
  890. Run("protocol_compiler --test_out $tmpdir "
  891. "--proto_path=$tmpdir foo.proto");
  892. ExpectNoErrors();
  893. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  894. }
  895. TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) {
  896. // Test that separating the flag value with a space works for
  897. // single-character flags.
  898. RegisterGenerator("test_generator", "-t",
  899. "output.test", "Test output.");
  900. CreateTempFile("foo.proto",
  901. "syntax = \"proto2\";\n"
  902. "message Foo {}\n");
  903. Run("protocol_compiler -t $tmpdir "
  904. "--proto_path=$tmpdir foo.proto");
  905. ExpectNoErrors();
  906. ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test");
  907. }
  908. TEST_F(CommandLineInterfaceTest, MissingValueError) {
  909. // Test that we get an error if a flag is missing its value.
  910. RegisterGenerator("test_generator", "--test_out",
  911. "output.test", "Test output.");
  912. Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto");
  913. ExpectErrorText("Missing value for flag: --test_out\n");
  914. }
  915. TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) {
  916. // Test that we get an error if the last argument is a flag requiring a
  917. // value.
  918. RegisterGenerator("test_generator", "--test_out",
  919. "output.test", "Test output.");
  920. Run("protocol_compiler --test_out");
  921. ExpectErrorText("Missing value for flag: --test_out\n");
  922. }
  923. // ===================================================================
  924. // Test for --encode and --decode. Note that it would be easier to do this
  925. // test as a shell script, but we'd like to be able to run the test on
  926. // platforms that don't have a Bourne-compatible shell available (especially
  927. // Windows/MSVC).
  928. class EncodeDecodeTest : public testing::Test {
  929. protected:
  930. virtual void SetUp() {
  931. duped_stdin_ = dup(STDIN_FILENO);
  932. }
  933. virtual void TearDown() {
  934. dup2(duped_stdin_, STDIN_FILENO);
  935. close(duped_stdin_);
  936. }
  937. void RedirectStdinFromText(const string& input) {
  938. string filename = TestTempDir() + "/test_stdin";
  939. File::WriteStringToFileOrDie(input, filename);
  940. GOOGLE_CHECK(RedirectStdinFromFile(filename));
  941. }
  942. bool RedirectStdinFromFile(const string& filename) {
  943. int fd = open(filename.c_str(), O_RDONLY);
  944. if (fd < 0) return false;
  945. dup2(fd, STDIN_FILENO);
  946. close(fd);
  947. return true;
  948. }
  949. // Remove '\r' characters from text.
  950. string StripCR(const string& text) {
  951. string result;
  952. for (int i = 0; i < text.size(); i++) {
  953. if (text[i] != '\r') {
  954. result.push_back(text[i]);
  955. }
  956. }
  957. return result;
  958. }
  959. enum Type { TEXT, BINARY };
  960. enum ReturnCode { SUCCESS, ERROR };
  961. bool Run(const string& command) {
  962. vector<string> args;
  963. args.push_back("protoc");
  964. SplitStringUsing(command, " ", &args);
  965. args.push_back("--proto_path=" + TestSourceDir());
  966. scoped_array<const char*> argv(new const char*[args.size()]);
  967. for (int i = 0; i < args.size(); i++) {
  968. argv[i] = args[i].c_str();
  969. }
  970. CommandLineInterface cli;
  971. cli.SetInputsAreProtoPathRelative(true);
  972. CaptureTestStdout();
  973. CaptureTestStderr();
  974. int result = cli.Run(args.size(), argv.get());
  975. captured_stdout_ = GetCapturedTestStdout();
  976. captured_stderr_ = GetCapturedTestStderr();
  977. return result == 0;
  978. }
  979. void ExpectStdoutMatchesBinaryFile(const string& filename) {
  980. string expected_output;
  981. ASSERT_TRUE(File::ReadFileToString(filename, &expected_output));
  982. // Don't use EXPECT_EQ because we don't want to print raw binary data to
  983. // stdout on failure.
  984. EXPECT_TRUE(captured_stdout_ == expected_output);
  985. }
  986. void ExpectStdoutMatchesTextFile(const string& filename) {
  987. string expected_output;
  988. ASSERT_TRUE(File::ReadFileToString(filename, &expected_output));
  989. ExpectStdoutMatchesText(expected_output);
  990. }
  991. void ExpectStdoutMatchesText(const string& expected_text) {
  992. EXPECT_EQ(StripCR(expected_text), StripCR(captured_stdout_));
  993. }
  994. void ExpectStderrMatchesText(const string& expected_text) {
  995. EXPECT_EQ(StripCR(expected_text), StripCR(captured_stderr_));
  996. }
  997. private:
  998. int duped_stdin_;
  999. string captured_stdout_;
  1000. string captured_stderr_;
  1001. };
  1002. TEST_F(EncodeDecodeTest, Encode) {
  1003. RedirectStdinFromFile(TestSourceDir() +
  1004. "/google/protobuf/testdata/text_format_unittest_data.txt");
  1005. EXPECT_TRUE(Run("google/protobuf/unittest.proto "
  1006. "--encode=protobuf_unittest.TestAllTypes"));
  1007. ExpectStdoutMatchesBinaryFile(TestSourceDir() +
  1008. "/google/protobuf/testdata/golden_message");
  1009. ExpectStderrMatchesText("");
  1010. }
  1011. TEST_F(EncodeDecodeTest, Decode) {
  1012. RedirectStdinFromFile(TestSourceDir() +
  1013. "/google/protobuf/testdata/golden_message");
  1014. EXPECT_TRUE(Run("google/protobuf/unittest.proto "
  1015. "--decode=protobuf_unittest.TestAllTypes"));
  1016. ExpectStdoutMatchesTextFile(TestSourceDir() +
  1017. "/google/protobuf/testdata/text_format_unittest_data.txt");
  1018. ExpectStderrMatchesText("");
  1019. }
  1020. TEST_F(EncodeDecodeTest, Partial) {
  1021. RedirectStdinFromText("");
  1022. EXPECT_TRUE(Run("google/protobuf/unittest.proto "
  1023. "--encode=protobuf_unittest.TestRequired"));
  1024. ExpectStdoutMatchesText("");
  1025. ExpectStderrMatchesText(
  1026. "warning: Input message is missing required fields: a, b, c\n");
  1027. }
  1028. TEST_F(EncodeDecodeTest, DecodeRaw) {
  1029. protobuf_unittest::TestAllTypes message;
  1030. message.set_optional_int32(123);
  1031. message.set_optional_string("foo");
  1032. string data;
  1033. message.SerializeToString(&data);
  1034. RedirectStdinFromText(data);
  1035. EXPECT_TRUE(Run("--decode_raw"));
  1036. ExpectStdoutMatchesText("1: 123\n"
  1037. "14: \"foo\"\n");
  1038. ExpectStderrMatchesText("");
  1039. }
  1040. TEST_F(EncodeDecodeTest, UnknownType) {
  1041. EXPECT_FALSE(Run("google/protobuf/unittest.proto "
  1042. "--encode=NoSuchType"));
  1043. ExpectStdoutMatchesText("");
  1044. ExpectStderrMatchesText("Type not defined: NoSuchType\n");
  1045. }
  1046. TEST_F(EncodeDecodeTest, ProtoParseError) {
  1047. EXPECT_FALSE(Run("google/protobuf/no_such_file.proto "
  1048. "--encode=NoSuchType"));
  1049. ExpectStdoutMatchesText("");
  1050. ExpectStderrMatchesText(
  1051. "google/protobuf/no_such_file.proto: File not found.\n");
  1052. }
  1053. } // anonymous namespace
  1054. } // namespace compiler
  1055. } // namespace protobuf
  1056. } // namespace google