Merge pull request #168 from cfallin/ruby-oneof
Support oneofs in MRI Ruby C extension.changes/73/215573/1
commit
17e4419188
17 changed files with 2348 additions and 262 deletions
@ -0,0 +1,67 @@ |
||||
syntax = "proto3"; |
||||
|
||||
package A.B.C; |
||||
|
||||
message TestMessage { |
||||
optional int32 optional_int32 = 1; |
||||
optional int64 optional_int64 = 2; |
||||
optional uint32 optional_uint32 = 3; |
||||
optional uint64 optional_uint64 = 4; |
||||
optional bool optional_bool = 5; |
||||
optional double optional_double = 6; |
||||
optional float optional_float = 7; |
||||
optional string optional_string = 8; |
||||
optional bytes optional_bytes = 9; |
||||
optional TestEnum optional_enum = 10; |
||||
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; |
||||
|
||||
oneof my_oneof { |
||||
int32 oneof_int32 = 41; |
||||
int64 oneof_int64 = 42; |
||||
uint32 oneof_uint32 = 43; |
||||
uint64 oneof_uint64 = 44; |
||||
bool oneof_bool = 45; |
||||
double oneof_double = 46; |
||||
float oneof_float = 47; |
||||
string oneof_string = 48; |
||||
bytes oneof_bytes = 49; |
||||
TestEnum oneof_enum = 50; |
||||
TestMessage oneof_msg = 51; |
||||
} |
||||
|
||||
map<int32, string> map_int32_string = 61; |
||||
map<int64, string> map_int64_string = 62; |
||||
map<uint32, string> map_uint32_string = 63; |
||||
map<uint64, string> map_uint64_string = 64; |
||||
map<bool, string> map_bool_string = 65; |
||||
map<string, string> map_string_string = 66; |
||||
map<string, TestMessage> map_string_msg = 67; |
||||
map<string, TestEnum> map_string_enum = 68; |
||||
map<string, int32> map_string_int32 = 69; |
||||
map<string, bool> map_string_bool = 70; |
||||
|
||||
message NestedMessage { |
||||
optional int32 foo = 1; |
||||
} |
||||
|
||||
optional NestedMessage nested_message = 80; |
||||
} |
||||
|
||||
enum TestEnum { |
||||
Default = 0; |
||||
A = 1; |
||||
B = 2; |
||||
C = 3; |
||||
} |
@ -0,0 +1,124 @@ |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# source: generated_code.proto |
||||
|
||||
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, :string, 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, :string, 29 |
||||
repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum" |
||||
repeated :repeated_msg, :message, 31, "A.B.C.TestMessage" |
||||
repeated :map_int32_string, :message, 61, "A.B.C.TestMessage.MapInt32StringEntry" |
||||
repeated :map_int64_string, :message, 62, "A.B.C.TestMessage.MapInt64StringEntry" |
||||
repeated :map_uint32_string, :message, 63, "A.B.C.TestMessage.MapUint32StringEntry" |
||||
repeated :map_uint64_string, :message, 64, "A.B.C.TestMessage.MapUint64StringEntry" |
||||
repeated :map_bool_string, :message, 65, "A.B.C.TestMessage.MapBoolStringEntry" |
||||
repeated :map_string_string, :message, 66, "A.B.C.TestMessage.MapStringStringEntry" |
||||
repeated :map_string_msg, :message, 67, "A.B.C.TestMessage.MapStringMsgEntry" |
||||
repeated :map_string_enum, :message, 68, "A.B.C.TestMessage.MapStringEnumEntry" |
||||
repeated :map_string_int32, :message, 69, "A.B.C.TestMessage.MapStringInt32Entry" |
||||
repeated :map_string_bool, :message, 70, "A.B.C.TestMessage.MapStringBoolEntry" |
||||
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, :string, 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.MapInt32StringEntry" do |
||||
optional :key, :int32, 1 |
||||
optional :value, :string, 2 |
||||
end |
||||
add_message "A.B.C.TestMessage.MapInt64StringEntry" do |
||||
optional :key, :int64, 1 |
||||
optional :value, :string, 2 |
||||
end |
||||
add_message "A.B.C.TestMessage.MapUint32StringEntry" do |
||||
optional :key, :uint32, 1 |
||||
optional :value, :string, 2 |
||||
end |
||||
add_message "A.B.C.TestMessage.MapUint64StringEntry" do |
||||
optional :key, :uint64, 1 |
||||
optional :value, :string, 2 |
||||
end |
||||
add_message "A.B.C.TestMessage.MapBoolStringEntry" do |
||||
optional :key, :bool, 1 |
||||
optional :value, :string, 2 |
||||
end |
||||
add_message "A.B.C.TestMessage.MapStringStringEntry" do |
||||
optional :key, :string, 1 |
||||
optional :value, :string, 2 |
||||
end |
||||
add_message "A.B.C.TestMessage.MapStringMsgEntry" do |
||||
optional :key, :string, 1 |
||||
optional :value, :message, 2, "A.B.C.TestMessage" |
||||
end |
||||
add_message "A.B.C.TestMessage.MapStringEnumEntry" do |
||||
optional :key, :string, 1 |
||||
optional :value, :enum, 2, "A.B.C.TestEnum" |
||||
end |
||||
add_message "A.B.C.TestMessage.MapStringInt32Entry" do |
||||
optional :key, :string, 1 |
||||
optional :value, :int32, 2 |
||||
end |
||||
add_message "A.B.C.TestMessage.MapStringBoolEntry" do |
||||
optional :key, :string, 1 |
||||
optional :value, :bool, 2 |
||||
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 |
||||
|
||||
module A |
||||
module B |
||||
module C |
||||
TestMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage").msgclass |
||||
TestMessage::MapInt32StringEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapInt32StringEntry").msgclass |
||||
TestMessage::MapInt64StringEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapInt64StringEntry").msgclass |
||||
TestMessage::MapUint32StringEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapUint32StringEntry").msgclass |
||||
TestMessage::MapUint64StringEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapUint64StringEntry").msgclass |
||||
TestMessage::MapBoolStringEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapBoolStringEntry").msgclass |
||||
TestMessage::MapStringStringEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapStringStringEntry").msgclass |
||||
TestMessage::MapStringMsgEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapStringMsgEntry").msgclass |
||||
TestMessage::MapStringEnumEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapStringEnumEntry").msgclass |
||||
TestMessage::MapStringInt32Entry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapStringInt32Entry").msgclass |
||||
TestMessage::MapStringBoolEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.MapStringBoolEntry").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 |
@ -0,0 +1,17 @@ |
||||
#!/usr/bin/ruby |
||||
|
||||
# generated_code.rb is in the same directory as this test. |
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) |
||||
|
||||
require 'generated_code' |
||||
require 'test/unit' |
||||
|
||||
class GeneratedCodeTest < Test::Unit::TestCase |
||||
def test_generated_msg |
||||
# just test that we can instantiate the message. The purpose of this test |
||||
# is to ensure that the output of the code generator is valid Ruby and |
||||
# successfully creates message definitions and classes, not to test every |
||||
# aspect of the extension (basic.rb is for that). |
||||
m = A::B::C::TestMessage.new() |
||||
end |
||||
end |
@ -0,0 +1,119 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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 <memory> |
||||
|
||||
#include <google/protobuf/compiler/ruby/ruby_generator.h> |
||||
#include <google/protobuf/compiler/command_line_interface.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
|
||||
#include <google/protobuf/testing/googletest.h> |
||||
#include <gtest/gtest.h> |
||||
#include <google/protobuf/testing/file.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace ruby { |
||||
namespace { |
||||
|
||||
string FindRubyTestDir() { |
||||
// Inspired by TestSourceDir() in src/google/protobuf/testing/googletest.cc.
|
||||
string prefix = "."; |
||||
while (!File::Exists(prefix + "/ruby/tests")) { |
||||
if (!File::Exists(prefix)) { |
||||
GOOGLE_LOG(FATAL) |
||||
<< "Could not find Ruby test directory. Please run tests from " |
||||
"somewhere within the protobuf source package."; |
||||
} |
||||
prefix += "/.."; |
||||
} |
||||
return prefix + "/ruby/tests"; |
||||
} |
||||
|
||||
// This test is a simple golden-file test over the output of the Ruby code
|
||||
// generator. When we make changes to the Ruby extension and alter the Ruby code
|
||||
// generator to use those changes, we should (i) manually test the output of the
|
||||
// code generator with the extension, and (ii) update the golden output above.
|
||||
// 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) { |
||||
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 + "/generated_code.proto", |
||||
&test_input, |
||||
true)); |
||||
GOOGLE_CHECK_OK(File::SetContents( |
||||
TestTempDir() + "/generated_code.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(), |
||||
"generated_code.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() + "/generated_code.rb", |
||||
&output, |
||||
true)); |
||||
string expected_output; |
||||
GOOGLE_CHECK_OK(File::GetContents( |
||||
ruby_tests + "/generated_code.rb", |
||||
&expected_output, |
||||
true)); |
||||
EXPECT_EQ(expected_output, output); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace ruby
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
Loading…
Reference in new issue