cpp_plugin_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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. // Author: kenton@google.com (Kenton Varda)
  31. //
  32. // TODO(kenton): Share code with the versions of this test in other languages?
  33. // It seemed like parameterizing it would add more complexity than it is
  34. // worth.
  35. #include <memory>
  36. #include <google/protobuf/compiler/cpp/cpp_generator.h>
  37. #include <google/protobuf/compiler/command_line_interface.h>
  38. #include <google/protobuf/io/zero_copy_stream.h>
  39. #include <google/protobuf/io/printer.h>
  40. #include <google/protobuf/testing/file.h>
  41. #include <google/protobuf/testing/file.h>
  42. #include <google/protobuf/testing/googletest.h>
  43. #include <gtest/gtest.h>
  44. namespace google {
  45. namespace protobuf {
  46. namespace compiler {
  47. namespace cpp {
  48. namespace {
  49. class TestGenerator : public CodeGenerator {
  50. public:
  51. TestGenerator() {}
  52. ~TestGenerator() {}
  53. virtual bool Generate(const FileDescriptor* file,
  54. const string& parameter,
  55. GeneratorContext* context,
  56. string* error) const {
  57. TryInsert("test.pb.h", "includes", context);
  58. TryInsert("test.pb.h", "namespace_scope", context);
  59. TryInsert("test.pb.h", "global_scope", context);
  60. TryInsert("test.pb.h", "class_scope:foo.Bar", context);
  61. TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", context);
  62. TryInsert("test.pb.cc", "includes", context);
  63. TryInsert("test.pb.cc", "namespace_scope", context);
  64. TryInsert("test.pb.cc", "global_scope", context);
  65. // Check field accessors for an optional int32:
  66. TryInsert("test.pb.h", "field_get:foo.Bar.optInt", context);
  67. TryInsert("test.pb.h", "field_set:foo.Bar.optInt", context);
  68. // Check field accessors for a repeated int32:
  69. TryInsert("test.pb.h", "field_get:foo.Bar.repeatedInt", context);
  70. TryInsert("test.pb.h", "field_set:foo.Bar.repeatedInt", context);
  71. // Check field accessors for a required string:
  72. TryInsert("test.pb.h", "field_get:foo.Bar.requiredString", context);
  73. TryInsert("test.pb.h", "field_set:foo.Bar.requiredString", context);
  74. TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context);
  75. TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context);
  76. TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredString", context);
  77. TryInsert("test.pb.h", "field_set_allocated:foo.Bar.requiredString",
  78. context);
  79. TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context);
  80. TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context);
  81. // Check field accessors for a repeated string:
  82. TryInsert("test.pb.h", "field_get:foo.Bar.repeatedString", context);
  83. TryInsert("test.pb.h", "field_set:foo.Bar.repeatedString", context);
  84. TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
  85. TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
  86. TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedString", context);
  87. TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
  88. TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
  89. // Check field accessors for an int inside oneof{}:
  90. TryInsert("test.pb.h", "field_get:foo.Bar.oneOfInt", context);
  91. TryInsert("test.pb.h", "field_set:foo.Bar.oneOfInt", context);
  92. // Check field accessors for a string inside oneof{}:
  93. TryInsert("test.pb.h", "field_get:foo.Bar.oneOfString", context);
  94. TryInsert("test.pb.h", "field_set:foo.Bar.oneOfString", context);
  95. TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context);
  96. TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context);
  97. TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfString", context);
  98. TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfString", context);
  99. TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context);
  100. TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context);
  101. // Check field accessors for an optional message:
  102. TryInsert("test.pb.h", "field_get:foo.Bar.optMessage", context);
  103. TryInsert("test.pb.h", "field_mutable:foo.Bar.optMessage", context);
  104. TryInsert("test.pb.h", "field_set_allocated:foo.Bar.optMessage", context);
  105. // Check field accessors for a repeated message:
  106. TryInsert("test.pb.h", "field_add:foo.Bar.repeatedMessage", context);
  107. TryInsert("test.pb.h", "field_get:foo.Bar.repeatedMessage", context);
  108. TryInsert("test.pb.h", "field_list:foo.Bar.repeatedMessage", context);
  109. TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedMessage", context);
  110. TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedMessage",
  111. context);
  112. // Check field accessors for a message inside oneof{}:
  113. TryInsert("test.pb.h", "field_get:foo.Bar.oneOfMessage", context);
  114. TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfMessage", context);
  115. TryInsert("test.pb.cc", "field_set_allocated:foo.Bar.oneOfMessage", context);
  116. // Check field accessors for an optional enum:
  117. TryInsert("test.pb.h", "field_get:foo.Bar.optEnum", context);
  118. TryInsert("test.pb.h", "field_set:foo.Bar.optEnum", context);
  119. // Check field accessors for a repeated enum:
  120. TryInsert("test.pb.h", "field_get:foo.Bar.repeatedEnum", context);
  121. TryInsert("test.pb.h", "field_set:foo.Bar.repeatedEnum", context);
  122. TryInsert("test.pb.h", "field_add:foo.Bar.repeatedEnum", context);
  123. TryInsert("test.pb.h", "field_list:foo.Bar.repeatedEnum", context);
  124. TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedEnum", context);
  125. // Check field accessors for an enum inside oneof{}:
  126. TryInsert("test.pb.h", "field_get:foo.Bar.oneOfEnum", context);
  127. TryInsert("test.pb.h", "field_set:foo.Bar.oneOfEnum", context);
  128. // Check field accessors for a required cord:
  129. TryInsert("test.pb.h", "field_get:foo.Bar.requiredCord", context);
  130. TryInsert("test.pb.h", "field_set:foo.Bar.requiredCord", context);
  131. TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredCord", context);
  132. // Check field accessors for a repeated cord:
  133. TryInsert("test.pb.h", "field_get:foo.Bar.repeatedCord", context);
  134. TryInsert("test.pb.h", "field_set:foo.Bar.repeatedCord", context);
  135. TryInsert("test.pb.h", "field_add:foo.Bar.repeatedCord", context);
  136. TryInsert("test.pb.h", "field_list:foo.Bar.repeatedCord", context);
  137. TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedCord", context);
  138. TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedCord", context);
  139. // Check field accessors for a cord inside oneof{}:
  140. TryInsert("test.pb.h", "field_get:foo.Bar.oneOfCord", context);
  141. TryInsert("test.pb.h", "field_set:foo.Bar.oneOfCord", context);
  142. TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfCord", context);
  143. return true;
  144. }
  145. void TryInsert(const string& filename, const string& insertion_point,
  146. GeneratorContext* context) const {
  147. std::unique_ptr<io::ZeroCopyOutputStream> output(
  148. context->OpenForInsert(filename, insertion_point));
  149. io::Printer printer(output.get(), '$');
  150. printer.Print("// inserted $name$\n", "name", insertion_point);
  151. }
  152. };
  153. // This test verifies that all the expected insertion points exist. It does
  154. // not verify that they are correctly-placed; that would require actually
  155. // compiling the output which is a bit more than I care to do for this test.
  156. TEST(CppPluginTest, PluginTest) {
  157. GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
  158. "syntax = \"proto2\";\n"
  159. "package foo;\n"
  160. "\n"
  161. "enum Thud { VALUE = 0; }\n"
  162. "\n"
  163. "message Bar {\n"
  164. " message Baz {}\n"
  165. " optional int32 optInt = 1;\n"
  166. " repeated int32 repeatedInt = 2;\n"
  167. "\n"
  168. " required string requiredString = 3;\n"
  169. " repeated string repeatedString = 4;\n"
  170. "\n"
  171. " optional Baz optMessage = 6;\n"
  172. " repeated Baz repeatedMessage = 7;\n"
  173. "\n"
  174. " optional Thud optEnum = 8;\n"
  175. " repeated Thud repeatedEnum = 9;\n"
  176. "\n"
  177. " required string requiredCord = 10 [\n"
  178. " ctype = CORD\n"
  179. " ];\n"
  180. " repeated string repeatedCord = 11 [\n"
  181. " ctype = CORD\n"
  182. " ];\n"
  183. "\n"
  184. " oneof Qux {\n"
  185. " int64 oneOfInt = 20;\n"
  186. " string oneOfString = 21;\n"
  187. " Baz oneOfMessage = 22;\n"
  188. " Thud oneOfEnum = 23;"
  189. " string oneOfCord = 24 [\n"
  190. " ctype = CORD\n"
  191. " ];\n"
  192. " }\n"
  193. "}\n",
  194. true));
  195. google::protobuf::compiler::CommandLineInterface cli;
  196. cli.SetInputsAreProtoPathRelative(true);
  197. CppGenerator cpp_generator;
  198. TestGenerator test_generator;
  199. cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
  200. cli.RegisterGenerator("--test_out", &test_generator, "");
  201. string proto_path = "-I" + TestTempDir();
  202. string cpp_out = "--cpp_out=" + TestTempDir();
  203. string test_out = "--test_out=" + TestTempDir();
  204. const char* argv[] = {
  205. "protoc",
  206. proto_path.c_str(),
  207. cpp_out.c_str(),
  208. test_out.c_str(),
  209. "test.proto"
  210. };
  211. EXPECT_EQ(0, cli.Run(5, argv));
  212. }
  213. } // namespace
  214. } // namespace cpp
  215. } // namespace compiler
  216. } // namespace protobuf
  217. } // namespace google