aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Fallin <cfallin@google.com>2015-01-14 15:44:46 -0800
committerChris Fallin <cfallin@google.com>2015-01-14 15:44:46 -0800
commit3f3820d8f8b5c0b67aadc25ad5a2e728b6a3fe79 (patch)
tree53afc636c0dfe600a05bc65531023886436b1af3
parent7c4bbf07a5eee1fd4f5c2d60be32b95c35b0ed1d (diff)
downloadprotobuf-3f3820d8f8b5c0b67aadc25ad5a2e728b6a3fe79.tar.gz
protobuf-3f3820d8f8b5c0b67aadc25ad5a2e728b6a3fe79.tar.bz2
protobuf-3f3820d8f8b5c0b67aadc25ad5a2e728b6a3fe79.zip
Two tests for Ruby code generator:
- A golden-file test that ensures protoc produces known-valid output. - A Ruby test that loads that golden file and ensures it actually works with the extension. This split strategy allows us to test end-to-end without needing to integrate the Ruby gem build system and the protoc build system. This is desirable because we do not want a gem build/install to depend on building protoc, and we do not want building protoc to depend on building and testing the gem.
-rw-r--r--ruby/google-protobuf.gemspec4
-rw-r--r--ruby/tests/generated_code.proto67
-rw-r--r--ruby/tests/generated_code.rb124
-rw-r--r--ruby/tests/generated_code_test.rb17
-rw-r--r--src/Makefile.am1
-rw-r--r--src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc116
6 files changed, 328 insertions, 1 deletions
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
index 87033ac4..7bfa533c 100644
--- a/ruby/google-protobuf.gemspec
+++ b/ruby/google-protobuf.gemspec
@@ -18,5 +18,7 @@ Gem::Specification.new do |s|
s.files = ["lib/google/protobuf.rb"] +
# extension C source
find_c_source("ext/google/protobuf_c")
- s.test_files = `git ls-files -- tests`.split
+ s.test_files = ["tests/basic.rb",
+ "tests/stress.rb",
+ "tests/generated_code_test.rb"]
end
diff --git a/ruby/tests/generated_code.proto b/ruby/tests/generated_code.proto
new file mode 100644
index 00000000..b1d63232
--- /dev/null
+++ b/ruby/tests/generated_code.proto
@@ -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;
+}
diff --git a/ruby/tests/generated_code.rb b/ruby/tests/generated_code.rb
new file mode 100644
index 00000000..db762ad9
--- /dev/null
+++ b/ruby/tests/generated_code.rb
@@ -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
diff --git a/ruby/tests/generated_code_test.rb b/ruby/tests/generated_code_test.rb
new file mode 100644
index 00000000..daef357a
--- /dev/null
+++ b/ruby/tests/generated_code_test.rb
@@ -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
diff --git a/src/Makefile.am b/src/Makefile.am
index 3a469fd7..6fd8bd2b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -458,6 +458,7 @@ protobuf_test_SOURCES = \
google/protobuf/compiler/java/java_plugin_unittest.cc \
google/protobuf/compiler/java/java_doc_comment_unittest.cc \
google/protobuf/compiler/python/python_plugin_unittest.cc \
+ google/protobuf/compiler/ruby/ruby_generator_unittest.cc \
$(COMMON_TEST_SOURCES)
nodist_protobuf_test_SOURCES = $(protoc_outputs)
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
new file mode 100644
index 00000000..971fb739
--- /dev/null
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -0,0 +1,116 @@
+// 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 python {
+namespace {
+
+class TestGenerator : public CodeGenerator {
+ public:
+ TestGenerator() {}
+ ~TestGenerator() {}
+
+ virtual bool Generate(const FileDescriptor* file,
+ const string& parameter,
+ GeneratorContext* context,
+ string* error) const {
+ TryInsert("test_pb2.py", "imports", context);
+ TryInsert("test_pb2.py", "module_scope", context);
+ TryInsert("test_pb2.py", "class_scope:foo.Bar", context);
+ TryInsert("test_pb2.py", "class_scope:foo.Bar.Baz", context);
+ return true;
+ }
+
+ void TryInsert(const string& filename, const string& insertion_point,
+ GeneratorContext* context) const {
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+ context->OpenForInsert(filename, insertion_point));
+ io::Printer printer(output.get(), '$');
+ printer.Print("// inserted $name$\n", "name", insertion_point);
+ }
+};
+
+// 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) {
+ google::protobuf::compiler::CommandLineInterface cli;
+ cli.SetInputsAreProtoPathRelative(true);
+
+ ruby::Generator ruby_generator;
+ cli.RegisterGenerator("--ruby_out", &ruby_generator, "");
+
+ string path_arg = "-I" + TestSourceDir() + "/ruby/tests";
+ string ruby_out = "--ruby_out=" + TestTempDir();
+ const char* argv[] = {
+ "protoc",
+ path_arg.c_str(),
+ ruby_out.c_str(),
+ "generated_code.proto",
+ };
+
+ EXPECT_EQ(0, cli.Run(4, argv));
+
+ string output;
+ GOOGLE_CHECK_OK(File::GetContents(TestTempDir() + "/generated_code.rb",
+ &output,
+ true));
+
+ string expected_output;
+ GOOGLE_CHECK_OK(File::GetContents(
+ TestSourceDir() + "/ruby/tests/generated_code.rb",
+ &expected_output,
+ true));
+
+ EXPECT_EQ(expected_output, output);
+}
+
+} // namespace
+} // namespace python
+} // namespace compiler
+} // namespace protobuf
+} // namespace google