aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHarshit Chopra <harshit@squareup.com>2017-08-25 12:11:15 -0700
committerHarshit Chopra <harshit@squareup.com>2018-09-27 14:21:16 -0400
commitd0535cc09e6eac1bddddd51c20b5738c0e841765 (patch)
treef712febe270ba656970f65b952114e14650103b6 /src
parent048f5c26a783f5f92061aec3aab19986e5c8d435 (diff)
downloadprotobuf-d0535cc09e6eac1bddddd51c20b5738c0e841765.tar.gz
protobuf-d0535cc09e6eac1bddddd51c20b5738c0e841765.tar.bz2
protobuf-d0535cc09e6eac1bddddd51c20b5738c0e841765.zip
Adds support for proto2 syntax for Ruby gem.
This change only adds basic proto2 support without advanced features like extensions, custom options, maps, etc. The protoc binary now generates ruby code for proto2 syntax. However, for now, it is restricted to proto2 files without advanced features like extensions, in which case it still errors out. This change also modifies the DSL to add proto messages to the DescriptorPool. There is a new DSL Builder#add_file to create a new FileDescriptor. With this, the generated ruby DSL looks something like: Google::Protobuf::DescriptorPool.generated_pool.build do add_file "test.proto" do add_message "foo" do optional :val, :int32, 1 end end end
Diffstat (limited to 'src')
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb112
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto68
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb77
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator.cc139
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc48
5 files changed, 363 insertions, 81 deletions
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb b/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
index 49b23fbe..0c9ed6fb 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
@@ -4,62 +4,64 @@
require 'google/protobuf'
Google::Protobuf::DescriptorPool.generated_pool.build do
- add_message "A.B.C.TestMessage" do
- optional :optional_int32, :int32, 1
- optional :optional_int64, :int64, 2
- optional :optional_uint32, :uint32, 3
- optional :optional_uint64, :uint64, 4
- optional :optional_bool, :bool, 5
- optional :optional_double, :double, 6
- optional :optional_float, :float, 7
- optional :optional_string, :string, 8
- optional :optional_bytes, :bytes, 9
- optional :optional_enum, :enum, 10, "A.B.C.TestEnum"
- optional :optional_msg, :message, 11, "A.B.C.TestMessage"
- repeated :repeated_int32, :int32, 21
- repeated :repeated_int64, :int64, 22
- repeated :repeated_uint32, :uint32, 23
- repeated :repeated_uint64, :uint64, 24
- repeated :repeated_bool, :bool, 25
- repeated :repeated_double, :double, 26
- repeated :repeated_float, :float, 27
- repeated :repeated_string, :string, 28
- repeated :repeated_bytes, :bytes, 29
- repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum"
- repeated :repeated_msg, :message, 31, "A.B.C.TestMessage"
- map :map_int32_string, :int32, :string, 61
- map :map_int64_string, :int64, :string, 62
- map :map_uint32_string, :uint32, :string, 63
- map :map_uint64_string, :uint64, :string, 64
- map :map_bool_string, :bool, :string, 65
- map :map_string_string, :string, :string, 66
- map :map_string_msg, :string, :message, 67, "A.B.C.TestMessage"
- map :map_string_enum, :string, :enum, 68, "A.B.C.TestEnum"
- map :map_string_int32, :string, :int32, 69
- map :map_string_bool, :string, :bool, 70
- optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage"
- oneof :my_oneof do
- optional :oneof_int32, :int32, 41
- optional :oneof_int64, :int64, 42
- optional :oneof_uint32, :uint32, 43
- optional :oneof_uint64, :uint64, 44
- optional :oneof_bool, :bool, 45
- optional :oneof_double, :double, 46
- optional :oneof_float, :float, 47
- optional :oneof_string, :string, 48
- optional :oneof_bytes, :bytes, 49
- optional :oneof_enum, :enum, 50, "A.B.C.TestEnum"
- optional :oneof_msg, :message, 51, "A.B.C.TestMessage"
+ add_file("ruby_generated_code.proto", :syntax => :proto3) do
+ add_message "A.B.C.TestMessage" do
+ optional :optional_int32, :int32, 1
+ optional :optional_int64, :int64, 2
+ optional :optional_uint32, :uint32, 3
+ optional :optional_uint64, :uint64, 4
+ optional :optional_bool, :bool, 5
+ optional :optional_double, :double, 6
+ optional :optional_float, :float, 7
+ optional :optional_string, :string, 8
+ optional :optional_bytes, :bytes, 9
+ optional :optional_enum, :enum, 10, "A.B.C.TestEnum"
+ optional :optional_msg, :message, 11, "A.B.C.TestMessage"
+ repeated :repeated_int32, :int32, 21
+ repeated :repeated_int64, :int64, 22
+ repeated :repeated_uint32, :uint32, 23
+ repeated :repeated_uint64, :uint64, 24
+ repeated :repeated_bool, :bool, 25
+ repeated :repeated_double, :double, 26
+ repeated :repeated_float, :float, 27
+ repeated :repeated_string, :string, 28
+ repeated :repeated_bytes, :bytes, 29
+ repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum"
+ repeated :repeated_msg, :message, 31, "A.B.C.TestMessage"
+ map :map_int32_string, :int32, :string, 61
+ map :map_int64_string, :int64, :string, 62
+ map :map_uint32_string, :uint32, :string, 63
+ map :map_uint64_string, :uint64, :string, 64
+ map :map_bool_string, :bool, :string, 65
+ map :map_string_string, :string, :string, 66
+ map :map_string_msg, :string, :message, 67, "A.B.C.TestMessage"
+ map :map_string_enum, :string, :enum, 68, "A.B.C.TestEnum"
+ map :map_string_int32, :string, :int32, 69
+ map :map_string_bool, :string, :bool, 70
+ optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage"
+ oneof :my_oneof do
+ optional :oneof_int32, :int32, 41
+ optional :oneof_int64, :int64, 42
+ optional :oneof_uint32, :uint32, 43
+ optional :oneof_uint64, :uint64, 44
+ optional :oneof_bool, :bool, 45
+ optional :oneof_double, :double, 46
+ optional :oneof_float, :float, 47
+ optional :oneof_string, :string, 48
+ optional :oneof_bytes, :bytes, 49
+ optional :oneof_enum, :enum, 50, "A.B.C.TestEnum"
+ optional :oneof_msg, :message, 51, "A.B.C.TestMessage"
+ end
+ end
+ add_message "A.B.C.TestMessage.NestedMessage" do
+ optional :foo, :int32, 1
+ end
+ add_enum "A.B.C.TestEnum" do
+ value :Default, 0
+ value :A, 1
+ value :B, 2
+ value :C, 3
end
- end
- add_message "A.B.C.TestMessage.NestedMessage" do
- optional :foo, :int32, 1
- end
- add_enum "A.B.C.TestEnum" do
- value :Default, 0
- value :A, 1
- value :B, 2
- value :C, 3
end
end
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto
new file mode 100644
index 00000000..8d3cc13e
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto
@@ -0,0 +1,68 @@
+syntax = "proto2";
+
+package A.B.C;
+
+message TestMessage {
+ optional int32 optional_int32 = 1 [default = 1];
+ optional int64 optional_int64 = 2 [default = 2];
+ optional uint32 optional_uint32 = 3 [default = 3];
+ optional uint64 optional_uint64 = 4 [default = 4];
+ optional bool optional_bool = 5 [default = true];
+ optional double optional_double = 6 [default = 6.0];
+ optional float optional_float = 7 [default = 7.0];
+ optional string optional_string = 8 [default = "default str"];
+ optional bytes optional_bytes = 9 [default = "\0\1\2\100fubar"];
+ optional TestEnum optional_enum = 10 [default = A];
+ optional TestMessage optional_msg = 11;
+
+ repeated int32 repeated_int32 = 21;
+ repeated int64 repeated_int64 = 22;
+ repeated uint32 repeated_uint32 = 23;
+ repeated uint64 repeated_uint64 = 24;
+ repeated bool repeated_bool = 25;
+ repeated double repeated_double = 26;
+ repeated float repeated_float = 27;
+ repeated string repeated_string = 28;
+ repeated bytes repeated_bytes = 29;
+ repeated TestEnum repeated_enum = 30;
+ repeated TestMessage repeated_msg = 31;
+
+ required int32 required_int32 = 41;
+ required int64 required_int64 = 42;
+ required uint32 required_uint32 = 43;
+ required uint64 required_uint64 = 44;
+ required bool required_bool = 45;
+ required double required_double = 46;
+ required float required_float = 47;
+ required string required_string = 48;
+ required bytes required_bytes = 49;
+ required TestEnum required_enum = 50;
+ required TestMessage required_msg = 51;
+
+ oneof my_oneof {
+ int32 oneof_int32 = 61;
+ int64 oneof_int64 = 62;
+ uint32 oneof_uint32 = 63;
+ uint64 oneof_uint64 = 64;
+ bool oneof_bool = 65;
+ double oneof_double = 66;
+ float oneof_float = 67;
+ string oneof_string = 68;
+ bytes oneof_bytes = 69;
+ TestEnum oneof_enum = 70;
+ TestMessage oneof_msg = 71;
+ }
+
+ message NestedMessage {
+ optional int32 foo = 1;
+ }
+
+ optional NestedMessage nested_message = 80;
+}
+
+enum TestEnum {
+ Default = 0;
+ A = 1;
+ B = 2;
+ C = 3;
+}
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb
new file mode 100644
index 00000000..15b340ad
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb
@@ -0,0 +1,77 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: ruby_generated_code_proto2.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+ add_file("ruby_generated_code_proto2.proto", :syntax => :proto2) do
+ add_message "A.B.C.TestMessage" do
+ optional :optional_int32, :int32, 1, default: 1
+ optional :optional_int64, :int64, 2, default: 2
+ optional :optional_uint32, :uint32, 3, default: 3
+ optional :optional_uint64, :uint64, 4, default: 4
+ optional :optional_bool, :bool, 5, default: true
+ optional :optional_double, :double, 6, default: 6
+ optional :optional_float, :float, 7, default: 7
+ optional :optional_string, :string, 8, default: "default str"
+ optional :optional_bytes, :bytes, 9, default: "\x00\x01\x02\x40\x66\x75\x62\x61\x72".force_encoding("ASCII-8BIT")
+ optional :optional_enum, :enum, 10, "A.B.C.TestEnum", default: 1
+ optional :optional_msg, :message, 11, "A.B.C.TestMessage"
+ repeated :repeated_int32, :int32, 21
+ repeated :repeated_int64, :int64, 22
+ repeated :repeated_uint32, :uint32, 23
+ repeated :repeated_uint64, :uint64, 24
+ repeated :repeated_bool, :bool, 25
+ repeated :repeated_double, :double, 26
+ repeated :repeated_float, :float, 27
+ repeated :repeated_string, :string, 28
+ repeated :repeated_bytes, :bytes, 29
+ repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum"
+ repeated :repeated_msg, :message, 31, "A.B.C.TestMessage"
+ required :required_int32, :int32, 41
+ required :required_int64, :int64, 42
+ required :required_uint32, :uint32, 43
+ required :required_uint64, :uint64, 44
+ required :required_bool, :bool, 45
+ required :required_double, :double, 46
+ required :required_float, :float, 47
+ required :required_string, :string, 48
+ required :required_bytes, :bytes, 49
+ required :required_enum, :enum, 50, "A.B.C.TestEnum"
+ required :required_msg, :message, 51, "A.B.C.TestMessage"
+ optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage"
+ oneof :my_oneof do
+ optional :oneof_int32, :int32, 61
+ optional :oneof_int64, :int64, 62
+ optional :oneof_uint32, :uint32, 63
+ optional :oneof_uint64, :uint64, 64
+ optional :oneof_bool, :bool, 65
+ optional :oneof_double, :double, 66
+ optional :oneof_float, :float, 67
+ optional :oneof_string, :string, 68
+ optional :oneof_bytes, :bytes, 69
+ optional :oneof_enum, :enum, 70, "A.B.C.TestEnum"
+ optional :oneof_msg, :message, 71, "A.B.C.TestMessage"
+ end
+ end
+ add_message "A.B.C.TestMessage.NestedMessage" do
+ optional :foo, :int32, 1
+ end
+ add_enum "A.B.C.TestEnum" do
+ value :Default, 0
+ value :A, 1
+ value :B, 2
+ value :C, 3
+ end
+ end
+end
+
+module A
+ module B
+ module C
+ TestMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage").msgclass
+ TestMessage::NestedMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.NestedMessage").msgclass
+ TestEnum = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestEnum").enummodule
+ end
+ end
+end
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc
index bd737c02..6b9ea822 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc
@@ -28,6 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <iomanip>
#include <sstream>
#include <google/protobuf/compiler/code_generator.h>
@@ -45,12 +46,13 @@ namespace compiler {
namespace ruby {
// Forward decls.
-std::string IntToString(int32 value);
+template<class numeric_type> std::string NumberToString(numeric_type value);
std::string GetRequireName(const std::string& proto_file);
std::string LabelForField(google::protobuf::FieldDescriptor* field);
std::string TypeName(google::protobuf::FieldDescriptor* field);
-void GenerateMessage(const google::protobuf::Descriptor* message,
- google::protobuf::io::Printer* printer);
+bool GenerateMessage(const google::protobuf::Descriptor* message,
+ google::protobuf::io::Printer* printer,
+ std::string* error);
void GenerateEnum(const google::protobuf::EnumDescriptor* en,
google::protobuf::io::Printer* printer);
void GenerateMessageAssignment(
@@ -61,8 +63,11 @@ void GenerateEnumAssignment(
const std::string& prefix,
const google::protobuf::EnumDescriptor* en,
google::protobuf::io::Printer* printer);
-
-std::string IntToString(int32 value) {
+std::string DefaultValueForField(
+ const google::protobuf::FieldDescriptor* field);
+
+template<class numeric_type>
+std::string NumberToString(numeric_type value) {
std::ostringstream os;
os << value;
return os.str();
@@ -110,6 +115,62 @@ std::string TypeName(const google::protobuf::FieldDescriptor* field) {
}
}
+string StringifySyntax(FileDescriptor::Syntax syntax) {
+ switch (syntax) {
+ case FileDescriptor::SYNTAX_PROTO2:
+ return "proto2";
+ case FileDescriptor::SYNTAX_PROTO3:
+ return "proto3";
+ case FileDescriptor::SYNTAX_UNKNOWN:
+ default:
+ GOOGLE_LOG(FATAL) << "Unsupported syntax; this generator only supports "
+ "proto2 and proto3 syntax.";
+ return "";
+ }
+}
+
+std::string DefaultValueForField(const google::protobuf::FieldDescriptor* field) {
+ switch(field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return NumberToString(field->default_value_int32());
+ case FieldDescriptor::CPPTYPE_INT64:
+ return NumberToString(field->default_value_int64());
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return NumberToString(field->default_value_uint32());
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return NumberToString(field->default_value_uint64());
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return NumberToString(field->default_value_float());
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return NumberToString(field->default_value_double());
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return field->default_value_bool() ? "true" : "false";
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return NumberToString(field->default_value_enum()->number());
+ case FieldDescriptor::CPPTYPE_STRING: {
+ std::ostringstream os;
+ string default_str = field->default_value_string();
+
+ if (field->type() == FieldDescriptor::TYPE_STRING) {
+ os << "\"" << default_str << "\"";
+ } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
+ os << "\"";
+
+ os.fill('0');
+ for (int i = 0; i < default_str.length(); ++i) {
+ // Write the hex form of each byte.
+ os << "\\x" << std::hex << std::setw(2)
+ << ((uint16) ((unsigned char) default_str.at(i)));
+ }
+ os << "\".force_encoding(\"ASCII-8BIT\")";
+ }
+
+ return os.str();
+ }
+ default: assert(false); return "";
+ }
+}
+
void GenerateField(const google::protobuf::FieldDescriptor* field,
google::protobuf::io::Printer* printer) {
@@ -124,7 +185,7 @@ void GenerateField(const google::protobuf::FieldDescriptor* field,
"name", field->name(),
"key_type", TypeName(key_field),
"value_type", TypeName(value_field),
- "number", IntToString(field->number()));
+ "number", NumberToString(field->number()));
if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
printer->Print(
@@ -146,19 +207,25 @@ void GenerateField(const google::protobuf::FieldDescriptor* field,
printer->Print(
":$type$, $number$",
"type", TypeName(field),
- "number", IntToString(field->number()));
+ "number", NumberToString(field->number()));
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
printer->Print(
- ", \"$subtype$\"\n",
+ ", \"$subtype$\"",
"subtype", field->message_type()->full_name());
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
printer->Print(
- ", \"$subtype$\"\n",
+ ", \"$subtype$\"",
"subtype", field->enum_type()->full_name());
- } else {
- printer->Print("\n");
}
+
+ if (field->has_default_value()) {
+ printer->Print(
+ ", default: $default$",
+ "default", DefaultValueForField(field));
+ }
+
+ printer->Print("\n");
}
}
@@ -178,13 +245,18 @@ void GenerateOneof(const google::protobuf::OneofDescriptor* oneof,
printer->Print("end\n");
}
-void GenerateMessage(const google::protobuf::Descriptor* message,
- google::protobuf::io::Printer* printer) {
-
+bool GenerateMessage(const google::protobuf::Descriptor* message,
+ google::protobuf::io::Printer* printer,
+ std::string* error) {
+ if (message->extension_range_count() > 0 || message->extension_count() > 0) {
+ *error = "Extensions are not yet supported for proto2 .proto files.";
+ return false;
+ }
+
// Don't generate MapEntry messages -- we use the Ruby extension's native
// support for map fields instead.
if (message->options().map_entry()) {
- return;
+ return true;
}
printer->Print(
@@ -208,11 +280,15 @@ void GenerateMessage(const google::protobuf::Descriptor* message,
printer->Print("end\n");
for (int i = 0; i < message->nested_type_count(); i++) {
- GenerateMessage(message->nested_type(i), printer);
+ if (!GenerateMessage(message->nested_type(i), printer, error)) {
+ return false;
+ }
}
for (int i = 0; i < message->enum_type_count(); i++) {
GenerateEnum(message->enum_type(i), printer);
}
+
+ return true;
}
void GenerateEnum(const google::protobuf::EnumDescriptor* en,
@@ -227,7 +303,7 @@ void GenerateEnum(const google::protobuf::EnumDescriptor* en,
printer->Print(
"value :$name$, $number$\n",
"name", value->name(),
- "number", IntToString(value->number()));
+ "number", NumberToString(value->number()));
}
printer->Outdent();
@@ -423,7 +499,8 @@ bool MaybeEmitDependency(const FileDescriptor* import,
const FileDescriptor* from,
io::Printer* printer,
string* error) {
- if (import->syntax() == FileDescriptor::SYNTAX_PROTO2) {
+ if (from->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
+ import->syntax() == FileDescriptor::SYNTAX_PROTO2) {
for (int i = 0; i < from->message_type_count(); i++) {
if (UsesTypeFromFile(from->message_type(i), import, error)) {
// Error text was already set by UsesTypeFromFile().
@@ -462,16 +539,29 @@ bool GenerateFile(const FileDescriptor* file, io::Printer* printer,
}
}
- printer->Print(
- "Google::Protobuf::DescriptorPool.generated_pool.build do\n");
+ // TODO: Remove this when ruby supports extensions for proto2 syntax.
+ if (file->extension_count() > 0) {
+ *error = "Extensions are not yet supported for proto2 .proto files.";
+ return false;
+ }
+
+ printer->Print("Google::Protobuf::DescriptorPool.generated_pool.build do\n");
+ printer->Indent();
+ printer->Print("add_file(\"$filename$\", :syntax => :$syntax$) do\n",
+ "filename", file->name(), "syntax",
+ StringifySyntax(file->syntax()));
printer->Indent();
for (int i = 0; i < file->message_type_count(); i++) {
- GenerateMessage(file->message_type(i), printer);
+ if (!GenerateMessage(file->message_type(i), printer, error)) {
+ return false;
+ }
}
for (int i = 0; i < file->enum_type_count(); i++) {
GenerateEnum(file->enum_type(i), printer);
}
printer->Outdent();
+ printer->Print("end\n");
+ printer->Outdent();
printer->Print(
"end\n\n");
@@ -492,10 +582,9 @@ bool Generator::Generate(
GeneratorContext* generator_context,
string* error) const {
- if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
- *error =
- "Can only generate Ruby code for proto3 .proto files.\n"
- "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n";
+ if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 &&
+ file->syntax() != FileDescriptor::SYNTAX_PROTO2) {
+ *error = "Invalid or unsupported proto syntax";
return false;
}
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
index 1aabe8aa..984d6b89 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -56,7 +56,7 @@ string FindRubyTestDir() {
// Some day, we may integrate build systems between protoc and the language
// extensions to the point where we can do this test in a more automated way.
-TEST(RubyGeneratorTest, GeneratorTest) {
+TEST(RubyGeneratorTest, Proto3GeneratorTest) {
string ruby_tests = FindRubyTestDir();
google::protobuf::compiler::CommandLineInterface cli;
@@ -102,6 +102,52 @@ TEST(RubyGeneratorTest, GeneratorTest) {
EXPECT_EQ(expected_output, output);
}
+TEST(RubyGeneratorTest, Proto2GeneratorTest) {
+ string ruby_tests = FindRubyTestDir();
+
+ google::protobuf::compiler::CommandLineInterface cli;
+ cli.SetInputsAreProtoPathRelative(true);
+
+ ruby::Generator ruby_generator;
+ cli.RegisterGenerator("--ruby_out", &ruby_generator, "");
+
+ // Copy generated_code.proto to the temporary test directory.
+ string test_input;
+ GOOGLE_CHECK_OK(File::GetContents(
+ ruby_tests + "/ruby_generated_code_proto2.proto",
+ &test_input,
+ true));
+ GOOGLE_CHECK_OK(File::SetContents(
+ TestTempDir() + "/ruby_generated_code_proto2.proto",
+ test_input,
+ true));
+
+ // Invoke the proto compiler (we will be inside TestTempDir() at this point).
+ string ruby_out = "--ruby_out=" + TestTempDir();
+ string proto_path = "--proto_path=" + TestTempDir();
+ const char* argv[] = {
+ "protoc",
+ ruby_out.c_str(),
+ proto_path.c_str(),
+ "ruby_generated_code_proto2.proto",
+ };
+
+ EXPECT_EQ(0, cli.Run(4, argv));
+
+ // Load the generated output and compare to the expected result.
+ string output;
+ GOOGLE_CHECK_OK(File::GetContents(
+ TestTempDir() + "/ruby_generated_code_proto2_pb.rb",
+ &output,
+ true));
+ string expected_output;
+ GOOGLE_CHECK_OK(File::GetContents(
+ ruby_tests + "/ruby_generated_code_proto2_pb.rb",
+ &expected_output,
+ true));
+ EXPECT_EQ(expected_output, output);
+}
+
} // namespace
} // namespace ruby
} // namespace compiler