protobuffy 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.travis.yml +12 -0
  4. data/.yardopts +5 -0
  5. data/CHANGES.md +261 -0
  6. data/CONTRIBUTING.md +16 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE.txt +14 -0
  9. data/README.md +58 -0
  10. data/Rakefile +61 -0
  11. data/bin/protoc-gen-ruby +17 -0
  12. data/bin/rpc_server +4 -0
  13. data/examples/bin/reverse-client-http +4 -0
  14. data/examples/bin/reverse-client-socket +4 -0
  15. data/examples/bin/reverse-client-zmq +4 -0
  16. data/examples/config.ru +6 -0
  17. data/examples/definitions/example/reverse.proto +12 -0
  18. data/examples/lib/example/reverse-client.rb +23 -0
  19. data/examples/lib/example/reverse-service.rb +9 -0
  20. data/examples/lib/example/reverse.pb.rb +36 -0
  21. data/lib/protobuf.rb +106 -0
  22. data/lib/protobuf/cli.rb +249 -0
  23. data/lib/protobuf/code_generator.rb +41 -0
  24. data/lib/protobuf/decoder.rb +74 -0
  25. data/lib/protobuf/deprecator.rb +42 -0
  26. data/lib/protobuf/descriptors.rb +3 -0
  27. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +52 -0
  28. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +249 -0
  29. data/lib/protobuf/encoder.rb +62 -0
  30. data/lib/protobuf/enum.rb +319 -0
  31. data/lib/protobuf/exceptions.rb +9 -0
  32. data/lib/protobuf/field.rb +74 -0
  33. data/lib/protobuf/field/base_field.rb +280 -0
  34. data/lib/protobuf/field/bool_field.rb +53 -0
  35. data/lib/protobuf/field/bytes_field.rb +81 -0
  36. data/lib/protobuf/field/double_field.rb +26 -0
  37. data/lib/protobuf/field/enum_field.rb +57 -0
  38. data/lib/protobuf/field/field_array.rb +86 -0
  39. data/lib/protobuf/field/fixed32_field.rb +25 -0
  40. data/lib/protobuf/field/fixed64_field.rb +29 -0
  41. data/lib/protobuf/field/float_field.rb +38 -0
  42. data/lib/protobuf/field/int32_field.rb +22 -0
  43. data/lib/protobuf/field/int64_field.rb +22 -0
  44. data/lib/protobuf/field/integer_field.rb +24 -0
  45. data/lib/protobuf/field/message_field.rb +66 -0
  46. data/lib/protobuf/field/sfixed32_field.rb +28 -0
  47. data/lib/protobuf/field/sfixed64_field.rb +29 -0
  48. data/lib/protobuf/field/signed_integer_field.rb +30 -0
  49. data/lib/protobuf/field/sint32_field.rb +22 -0
  50. data/lib/protobuf/field/sint64_field.rb +22 -0
  51. data/lib/protobuf/field/string_field.rb +35 -0
  52. data/lib/protobuf/field/uint32_field.rb +22 -0
  53. data/lib/protobuf/field/uint64_field.rb +22 -0
  54. data/lib/protobuf/field/varint_field.rb +68 -0
  55. data/lib/protobuf/generators/base.rb +71 -0
  56. data/lib/protobuf/generators/enum_generator.rb +42 -0
  57. data/lib/protobuf/generators/extension_generator.rb +28 -0
  58. data/lib/protobuf/generators/field_generator.rb +132 -0
  59. data/lib/protobuf/generators/file_generator.rb +140 -0
  60. data/lib/protobuf/generators/group_generator.rb +113 -0
  61. data/lib/protobuf/generators/message_generator.rb +99 -0
  62. data/lib/protobuf/generators/printable.rb +161 -0
  63. data/lib/protobuf/generators/service_generator.rb +27 -0
  64. data/lib/protobuf/http.rb +20 -0
  65. data/lib/protobuf/lifecycle.rb +46 -0
  66. data/lib/protobuf/logger.rb +86 -0
  67. data/lib/protobuf/message.rb +182 -0
  68. data/lib/protobuf/message/fields.rb +122 -0
  69. data/lib/protobuf/message/serialization.rb +84 -0
  70. data/lib/protobuf/optionable.rb +23 -0
  71. data/lib/protobuf/rpc/buffer.rb +79 -0
  72. data/lib/protobuf/rpc/client.rb +168 -0
  73. data/lib/protobuf/rpc/connector.rb +21 -0
  74. data/lib/protobuf/rpc/connectors/base.rb +54 -0
  75. data/lib/protobuf/rpc/connectors/common.rb +172 -0
  76. data/lib/protobuf/rpc/connectors/http.rb +90 -0
  77. data/lib/protobuf/rpc/connectors/socket.rb +73 -0
  78. data/lib/protobuf/rpc/connectors/zmq.rb +205 -0
  79. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +47 -0
  80. data/lib/protobuf/rpc/env.rb +58 -0
  81. data/lib/protobuf/rpc/error.rb +28 -0
  82. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  83. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  84. data/lib/protobuf/rpc/middleware.rb +25 -0
  85. data/lib/protobuf/rpc/middleware/exception_handler.rb +36 -0
  86. data/lib/protobuf/rpc/middleware/logger.rb +91 -0
  87. data/lib/protobuf/rpc/middleware/request_decoder.rb +83 -0
  88. data/lib/protobuf/rpc/middleware/response_encoder.rb +88 -0
  89. data/lib/protobuf/rpc/middleware/runner.rb +18 -0
  90. data/lib/protobuf/rpc/rpc.pb.rb +53 -0
  91. data/lib/protobuf/rpc/server.rb +39 -0
  92. data/lib/protobuf/rpc/servers/http/server.rb +101 -0
  93. data/lib/protobuf/rpc/servers/http_runner.rb +34 -0
  94. data/lib/protobuf/rpc/servers/socket/server.rb +113 -0
  95. data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
  96. data/lib/protobuf/rpc/servers/socket_runner.rb +34 -0
  97. data/lib/protobuf/rpc/servers/zmq/broker.rb +155 -0
  98. data/lib/protobuf/rpc/servers/zmq/server.rb +313 -0
  99. data/lib/protobuf/rpc/servers/zmq/util.rb +47 -0
  100. data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
  101. data/lib/protobuf/rpc/servers/zmq_runner.rb +51 -0
  102. data/lib/protobuf/rpc/service.rb +179 -0
  103. data/lib/protobuf/rpc/service_directory.rb +245 -0
  104. data/lib/protobuf/rpc/service_dispatcher.rb +46 -0
  105. data/lib/protobuf/rpc/service_filters.rb +273 -0
  106. data/lib/protobuf/rpc/stat.rb +148 -0
  107. data/lib/protobuf/socket.rb +22 -0
  108. data/lib/protobuf/tasks.rb +1 -0
  109. data/lib/protobuf/tasks/compile.rake +61 -0
  110. data/lib/protobuf/version.rb +3 -0
  111. data/lib/protobuf/wire_type.rb +10 -0
  112. data/lib/protobuf/zmq.rb +21 -0
  113. data/proto/dynamic_discovery.proto +44 -0
  114. data/proto/google/protobuf/compiler/plugin.proto +147 -0
  115. data/proto/google/protobuf/descriptor.proto +620 -0
  116. data/proto/rpc.proto +62 -0
  117. data/protobuffy.gemspec +37 -0
  118. data/spec/benchmark/tasks.rb +113 -0
  119. data/spec/bin/protoc-gen-ruby_spec.rb +18 -0
  120. data/spec/data/data.bin +3 -0
  121. data/spec/data/types.bin +0 -0
  122. data/spec/encoding/all_types_spec.rb +91 -0
  123. data/spec/encoding/extreme_values_spec.rb +0 -0
  124. data/spec/functional/socket_server_spec.rb +59 -0
  125. data/spec/functional/zmq_server_spec.rb +103 -0
  126. data/spec/lib/protobuf/cli_spec.rb +267 -0
  127. data/spec/lib/protobuf/code_generator_spec.rb +60 -0
  128. data/spec/lib/protobuf/enum_spec.rb +239 -0
  129. data/spec/lib/protobuf/field/int32_field_spec.rb +7 -0
  130. data/spec/lib/protobuf/field/string_field_spec.rb +46 -0
  131. data/spec/lib/protobuf/field_spec.rb +194 -0
  132. data/spec/lib/protobuf/generators/base_spec.rb +87 -0
  133. data/spec/lib/protobuf/generators/enum_generator_spec.rb +68 -0
  134. data/spec/lib/protobuf/generators/extension_generator_spec.rb +43 -0
  135. data/spec/lib/protobuf/generators/field_generator_spec.rb +99 -0
  136. data/spec/lib/protobuf/generators/file_generator_spec.rb +29 -0
  137. data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
  138. data/spec/lib/protobuf/generators/service_generator_spec.rb +43 -0
  139. data/spec/lib/protobuf/lifecycle_spec.rb +89 -0
  140. data/spec/lib/protobuf/logger_spec.rb +136 -0
  141. data/spec/lib/protobuf/message_spec.rb +368 -0
  142. data/spec/lib/protobuf/optionable_spec.rb +46 -0
  143. data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
  144. data/spec/lib/protobuf/rpc/connector_spec.rb +26 -0
  145. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
  146. data/spec/lib/protobuf/rpc/connectors/common_spec.rb +170 -0
  147. data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +13 -0
  148. data/spec/lib/protobuf/rpc/connectors/http_spec.rb +61 -0
  149. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +24 -0
  150. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +129 -0
  151. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
  152. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
  153. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
  154. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +75 -0
  155. data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +104 -0
  156. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
  157. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +41 -0
  158. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
  159. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
  160. data/spec/lib/protobuf/rpc/service_directory_spec.rb +295 -0
  161. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +52 -0
  162. data/spec/lib/protobuf/rpc/service_filters_spec.rb +484 -0
  163. data/spec/lib/protobuf/rpc/service_spec.rb +161 -0
  164. data/spec/lib/protobuf/rpc/stat_spec.rb +151 -0
  165. data/spec/lib/protobuf_spec.rb +78 -0
  166. data/spec/spec_helper.rb +57 -0
  167. data/spec/support/all.rb +7 -0
  168. data/spec/support/packed_field.rb +22 -0
  169. data/spec/support/server.rb +94 -0
  170. data/spec/support/test/all_types.data.bin +0 -0
  171. data/spec/support/test/all_types.data.txt +119 -0
  172. data/spec/support/test/defaults.pb.rb +25 -0
  173. data/spec/support/test/defaults.proto +9 -0
  174. data/spec/support/test/enum.pb.rb +59 -0
  175. data/spec/support/test/enum.proto +34 -0
  176. data/spec/support/test/extended.pb.rb +22 -0
  177. data/spec/support/test/extended.proto +10 -0
  178. data/spec/support/test/extreme_values.data.bin +0 -0
  179. data/spec/support/test/google_unittest.pb.rb +543 -0
  180. data/spec/support/test/google_unittest.proto +713 -0
  181. data/spec/support/test/google_unittest_import.pb.rb +37 -0
  182. data/spec/support/test/google_unittest_import.proto +64 -0
  183. data/spec/support/test/google_unittest_import_public.pb.rb +8 -0
  184. data/spec/support/test/google_unittest_import_public.proto +38 -0
  185. data/spec/support/test/multi_field_extensions.pb.rb +56 -0
  186. data/spec/support/test/multi_field_extensions.proto +33 -0
  187. data/spec/support/test/resource.pb.rb +117 -0
  188. data/spec/support/test/resource.proto +94 -0
  189. data/spec/support/test/resource_service.rb +26 -0
  190. data/spec/support/test_app_file.rb +2 -0
  191. data/spec/support/tolerance_matcher.rb +40 -0
  192. metadata +367 -0
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ require 'protobuf/generators/field_generator'
4
+
5
+ describe ::Protobuf::Generators::FieldGenerator do
6
+
7
+ let(:label_enum) { :LABEL_OPTIONAL }
8
+ let(:name) { 'foo_bar' }
9
+ let(:number) { 3 }
10
+ let(:type_enum) { :TYPE_STRING }
11
+ let(:type_name) { nil }
12
+ let(:default_value) { nil }
13
+ let(:extendee) { nil }
14
+ let(:field_options) { {} }
15
+
16
+ let(:field_fields) { { :label => label_enum,
17
+ :name => name,
18
+ :number => number,
19
+ :type => type_enum,
20
+ :type_name => type_name,
21
+ :default_value => default_value,
22
+ :extendee => extendee,
23
+ :options => field_options } }
24
+
25
+ let(:field) { ::Google::Protobuf::FieldDescriptorProto.new(field_fields) }
26
+
27
+ describe '#compile' do
28
+ subject { described_class.new(field).to_s }
29
+
30
+ it { should eq "optional :string, :foo_bar, 3\n" }
31
+
32
+ context 'when the type is another message' do
33
+ let(:type_enum) { :TYPE_MESSAGE }
34
+ let(:type_name) { '.foo.bar.Baz' }
35
+
36
+ it { should eq "optional ::Foo::Bar::Baz, :foo_bar, 3\n" }
37
+ end
38
+
39
+ context 'when a default value is used' do
40
+ let(:type_enum) { :TYPE_INT32 }
41
+ let(:default_value) { '42' }
42
+ it { should eq "optional :int32, :foo_bar, 3, :default => 42\n" }
43
+
44
+ context 'when type is an enum' do
45
+ let(:type_enum) { :TYPE_ENUM }
46
+ let(:type_name) { '.foo.bar.Baz' }
47
+ let(:default_value) { 'QUUX' }
48
+
49
+ it { should eq "optional ::Foo::Bar::Baz, :foo_bar, 3, :default => ::Foo::Bar::Baz::QUUX\n" }
50
+ end
51
+
52
+ context 'when the type is a string' do
53
+ let(:type_enum) { :TYPE_STRING }
54
+ let(:default_value) { "a default \"string\"" }
55
+
56
+ it { should eq %Q{optional :string, :foo_bar, 3, :default => "a default \"string\""\n} }
57
+ end
58
+
59
+ context 'when float or double field type' do
60
+ let(:type_enum) { :TYPE_DOUBLE }
61
+
62
+ context 'when the default value is "nan"' do
63
+ let(:default_value) { 'nan' }
64
+ it { should match(/::Float::NAN/) }
65
+ end
66
+
67
+ context 'when the default value is "inf"' do
68
+ let(:default_value) { 'inf' }
69
+ it { should match(/::Float::INFINITY/) }
70
+ end
71
+
72
+ context 'when the default value is "-inf"' do
73
+ let(:default_value) { '-inf' }
74
+ it { should match(/-::Float::INFINITY/) }
75
+ end
76
+ end
77
+ end
78
+
79
+ context 'when the field is an extension' do
80
+ let(:extendee) { 'foo.bar.Baz' }
81
+
82
+ it { should eq "optional :string, :foo_bar, 3, :extension => true\n" }
83
+ end
84
+
85
+ context 'when field is packed' do
86
+ let(:field_options) { { :packed => true } }
87
+
88
+ it { should eq "optional :string, :foo_bar, 3, :packed => true\n" }
89
+ end
90
+
91
+ context 'when field is deprecated' do
92
+ let(:field_options) { { :deprecated => true } }
93
+
94
+ it { should eq "optional :string, :foo_bar, 3, :deprecated => true\n" }
95
+ end
96
+ end
97
+
98
+ end
99
+
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ require 'protobuf/generators/file_generator'
4
+
5
+ describe ::Protobuf::Generators::FileGenerator do
6
+
7
+ let(:base_descriptor_fields) { { :name => 'test/foo.proto' } }
8
+ let(:descriptor_fields) { base_descriptor_fields }
9
+ let(:file_descriptor) { ::Google::Protobuf::FileDescriptorProto.new(descriptor_fields) }
10
+
11
+ subject { described_class.new(file_descriptor) }
12
+ its(:file_name) { should eq 'test/foo.pb.rb' }
13
+
14
+ describe '#print_import_requires' do
15
+ let(:descriptor_fields) do
16
+ base_descriptor_fields.merge!({ :dependency => [ 'test/bar.proto',
17
+ 'test/baz.proto' ] })
18
+ end
19
+
20
+ it 'prints a ruby require for each dependency' do
21
+ subject.should_receive(:print_require).with('test/bar.pb')
22
+ subject.should_receive(:print_require).with('test/baz.pb')
23
+ subject.print_import_requires
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ require 'protobuf/generators/service_generator'
4
+
5
+ describe ::Protobuf::Generators::ServiceGenerator do
6
+
7
+ let(:methods) {
8
+ [
9
+ { :name => 'Search', :input_type => 'FooRequest', :output_type => 'FooResponse' },
10
+ { :name => 'FooBar', :input_type => '.foo.Request', :output_type => '.bar.Response' }
11
+ ]
12
+ }
13
+ let(:service_fields) { { :name => 'TestService',
14
+ :method => methods } }
15
+
16
+ let(:service) { ::Google::Protobuf::ServiceDescriptorProto.new(service_fields) }
17
+
18
+ subject { described_class.new(service) }
19
+
20
+ describe '#compile' do
21
+ let(:compiled) {
22
+ %q{class TestService < ::Protobuf::Rpc::Service
23
+ rpc :search, FooRequest, FooResponse
24
+ rpc :foo_bar, ::Foo::Request, ::Bar::Response
25
+ end
26
+
27
+ }
28
+ }
29
+
30
+ it 'compiles the service and it\'s rpc methods' do
31
+ subject.compile
32
+ subject.to_s.should eq(compiled)
33
+ end
34
+ end
35
+
36
+ describe '#build_method' do
37
+ it 'returns a string identifying the given method descriptor' do
38
+ subject.build_method(service.method.first).should eq("rpc :search, FooRequest, FooResponse")
39
+ end
40
+ end
41
+
42
+ end
43
+
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+ require 'protobuf/lifecycle'
3
+
4
+ describe ::Protobuf::Lifecycle do
5
+ subject { described_class }
6
+
7
+ before(:each) do
8
+ ::ActiveSupport::Notifications.notifier = ::ActiveSupport::Notifications::Fanout.new
9
+ end
10
+
11
+ it "registers a string as the event_name" do
12
+ ::ActiveSupport::Notifications.should_receive(:subscribe).with("something")
13
+ subject.register("something") { true }
14
+ end
15
+
16
+ it "only registers blocks for event callbacks" do
17
+ expect {
18
+ subject.register("something")
19
+ }.to raise_error( /block/ )
20
+ end
21
+
22
+ it "calls the registered block when triggered" do
23
+ this = nil
24
+ subject.register("this") do
25
+ this = "not nil"
26
+ end
27
+
28
+ subject.trigger("this")
29
+ this.should_not be_nil
30
+ this.should eq("not nil")
31
+ end
32
+
33
+ it "calls multiple registered blocks when triggered" do
34
+ this = nil
35
+ that = nil
36
+
37
+ subject.register("this") do
38
+ this = "not nil"
39
+ end
40
+
41
+ subject.register("this") do
42
+ that = "not nil"
43
+ end
44
+
45
+ subject.trigger("this")
46
+ this.should_not be_nil
47
+ this.should eq("not nil")
48
+ that.should_not be_nil
49
+ that.should eq("not nil")
50
+ end
51
+
52
+ context 'when the registered block has arity' do
53
+ context 'and the triggered event does not have args' do
54
+ it 'does not pass the args' do
55
+ outer_bar = nil
56
+
57
+ subject.register('foo') do |bar|
58
+ bar.should be_nil
59
+ outer_bar = 'triggered'
60
+ end
61
+
62
+ subject.trigger('foo')
63
+ outer_bar.should eq 'triggered'
64
+ end
65
+ end
66
+
67
+ context 'and the triggered event has arguments' do
68
+ it 'does not pass the args' do
69
+ outer_bar = nil
70
+
71
+ subject.register('foo') do |bar|
72
+ bar.should_not be_nil
73
+ outer_bar = bar
74
+ end
75
+
76
+ subject.trigger('foo', 'baz')
77
+ outer_bar.should eq 'baz'
78
+ end
79
+ end
80
+ end
81
+
82
+ context "normalized event names" do
83
+ specify { subject.normalized_event_name(:derp).should eq("derp") }
84
+ specify { subject.normalized_event_name(:Derp).should eq("derp") }
85
+ specify { subject.normalized_event_name("DERP").should eq("derp") }
86
+ specify { subject.normalized_event_name("derp").should eq("derp") }
87
+ end
88
+
89
+ end
@@ -0,0 +1,136 @@
1
+ require 'protobuf/logger'
2
+ require 'stringio'
3
+ require 'fileutils'
4
+
5
+ describe Protobuf::Logger do
6
+
7
+ subject { Protobuf::Logger }
8
+
9
+ before(:each) do
10
+ Protobuf::Logger.reset_device!
11
+ Protobuf::Logger.file = '/dev/null'
12
+ Protobuf::Logger.level = ::Logger::INFO
13
+ end
14
+
15
+ after(:all) do
16
+ ::FileUtils.rm_f('myfile.log')
17
+ end
18
+
19
+ describe '.instance' do
20
+
21
+ it 'doesn\'t create a logger if the file was not set' do
22
+ subject.file = nil
23
+ subject.instance.should be_nil
24
+ end
25
+
26
+ it 'doesn\'t create a logger if the level was not set' do
27
+ subject.level = nil
28
+ subject.instance.should be_nil
29
+ end
30
+
31
+ it 'gets a new instance of the logger when file and level are set' do
32
+ subject.file.should_not be_nil
33
+ subject.level.should_not be_nil
34
+ subject.instance.should_not be_nil
35
+ end
36
+
37
+ it 'keeps the same object from multiple calls to instance' do
38
+ subject.instance === subject.instance
39
+ end
40
+
41
+ end
42
+
43
+ describe '.configure' do
44
+ before(:each) { subject.reset_device! }
45
+ it 'sets the file and level in one call' do
46
+ subject.file.should_not be
47
+ subject.level.should_not be
48
+ subject.instance.should_not be
49
+ subject.configure :file => 'myfile.log', :level => ::Logger::WARN
50
+ subject.file.should == 'myfile.log'
51
+ subject.level.should == ::Logger::WARN
52
+ subject.instance.level.should == ::Logger::WARN
53
+ end
54
+
55
+ end
56
+
57
+ describe '.reset_device!' do
58
+
59
+ it 'resets the logger instance, file, and level' do
60
+ subject.instance.should be
61
+ subject.file.should be
62
+ subject.level.should be
63
+ subject.reset_device!
64
+ subject.instance.should_not be
65
+ subject.file.should_not be
66
+ subject.level.should_not be
67
+ end
68
+
69
+ end
70
+
71
+ context 'when logging' do
72
+
73
+ it 'doesn\'t raise errors when log instance is nil' do
74
+ subject.reset_device!
75
+ subject.instance.should be_nil
76
+ expect {
77
+ subject.debug 'No errors here'
78
+ subject.info 'No errors here'
79
+ subject.warn 'No errors here'
80
+ subject.error 'No errors here'
81
+ subject.fatal 'No errors here'
82
+ subject.add 'No errors here'
83
+ subject.log 'No errors here'
84
+ }.to_not raise_error
85
+ end
86
+
87
+ it 'logs correctly when instance is valid' do
88
+ subject.instance.should_not be_nil
89
+ subject.instance.should_receive(:info).with('Should log great')
90
+ subject.info 'Should log great'
91
+ end
92
+
93
+ end
94
+
95
+ describe Protobuf::Logger::LogMethods do
96
+
97
+ context 'when included in another class' do
98
+
99
+ before(:all) do
100
+ class MyTestClass
101
+ include Protobuf::Logger::LogMethods
102
+ end
103
+ end
104
+
105
+ subject { MyTestClass.new }
106
+
107
+ it { should respond_to(:log_debug) }
108
+ it { should respond_to(:log_info) }
109
+ it { should respond_to(:log_warn) }
110
+ it { should respond_to(:log_error) }
111
+ it { should respond_to(:log_fatal) }
112
+ it { should respond_to(:log_add) }
113
+ it { should respond_to(:log_log) }
114
+
115
+ context '#log_exception' do
116
+ it 'logs the exception message as an error and backtrace as debug' do
117
+ subject.should_receive(:log_error).twice
118
+ subject.should_receive(:log_debug)
119
+ subject.log_exception(RuntimeError.new('this is an exception'))
120
+ end
121
+ end
122
+
123
+ its(:log_signature) { should eq "[MyTestClass]" }
124
+ describe '#sign_message' do
125
+ specify { subject.sign_message("this is a test").should eq "[MyTestClass] this is a test" }
126
+ specify { subject.class.sign_message("this is a test").should eq "[MyTestClass] this is a test" }
127
+ end
128
+
129
+ it 'passes all embedded log calls to Logger instance' do
130
+ Protobuf::Logger.instance.should_receive(:debug).with('[MyTestClass] log this')
131
+ subject.log_debug('log this')
132
+ end
133
+
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,368 @@
1
+ require 'spec_helper'
2
+
3
+ describe Protobuf::Message do
4
+
5
+ describe '.decode' do
6
+ let(:message) { ::Test::Resource.new(:name => "Jim") }
7
+
8
+ it 'creates a new message object decoded from the given bytes' do
9
+ ::Test::Resource.decode(message.encode).should eq message
10
+ end
11
+ end
12
+
13
+ describe 'defining a new field' do
14
+ context 'when defining a field with a tag that has already been used' do
15
+ it 'raises a TagCollisionError' do
16
+ expect {
17
+ Class.new(Protobuf::Message) do
18
+ optional ::Protobuf::Field::Int32Field, :foo, 1
19
+ optional ::Protobuf::Field::Int32Field, :bar, 1
20
+ end
21
+ }.to raise_error(Protobuf::TagCollisionError, /Field number 1 has already been used/)
22
+ end
23
+ end
24
+
25
+ context 'when defining an extension field with a tag that has already been used' do
26
+ it 'raises a TagCollisionError' do
27
+ expect {
28
+ Class.new(Protobuf::Message) do
29
+ extensions 100...110
30
+ optional ::Protobuf::Field::Int32Field, :foo, 100
31
+ optional ::Protobuf::Field::Int32Field, :bar, 100, :extension => true
32
+ end
33
+ }.to raise_error(Protobuf::TagCollisionError, /Field number 100 has already been used/)
34
+ end
35
+ end
36
+
37
+ context 'when defining a field with a name that has already been used' do
38
+ it 'raises a DuplicateFieldNameError' do
39
+ expect {
40
+ Class.new(Protobuf::Message) do
41
+ optional ::Protobuf::Field::Int32Field, :foo, 1
42
+ optional ::Protobuf::Field::Int32Field, :foo, 2
43
+ end
44
+ }.to raise_error(Protobuf::DuplicateFieldNameError, /Field name foo has already been used/)
45
+ end
46
+ end
47
+
48
+ context 'when defining an extension field with a name that has already been used' do
49
+ it 'raises a DuplicateFieldNameError' do
50
+ expect {
51
+ Class.new(Protobuf::Message) do
52
+ extensions 100...110
53
+ optional ::Protobuf::Field::Int32Field, :foo, 1
54
+ optional ::Protobuf::Field::Int32Field, :foo, 100, :extension => true
55
+ end
56
+ }.to raise_error(Protobuf::DuplicateFieldNameError, /Field name foo has already been used/)
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '.encode' do
62
+ let(:values) { { :name => "Jim" } }
63
+
64
+ it 'creates a new message object with the given values and returns the encoded bytes' do
65
+ ::Test::Resource.encode(values).should eq ::Test::Resource.new(values).encode
66
+ end
67
+ end
68
+
69
+ describe '#initialize' do
70
+ it "initializes the enum getter to 0" do
71
+ test_enum = Test::EnumTestMessage.new
72
+ test_enum.non_default_enum.should eq(0)
73
+ end
74
+
75
+ it "exposes the enum getter raw value through ! method" do
76
+ test_enum = Test::EnumTestMessage.new
77
+ test_enum.non_default_enum!.should be_nil
78
+ end
79
+
80
+ it "exposes the enum getter raw value through ! method (when set)" do
81
+ test_enum = Test::EnumTestMessage.new
82
+ test_enum.non_default_enum = 1
83
+ test_enum.non_default_enum!.should eq(1)
84
+ end
85
+
86
+ it "does not try to set attributes which have nil values" do
87
+ Test::EnumTestMessage.any_instance.should_not_receive("non_default_enum=")
88
+ Test::EnumTestMessage.new(:non_default_enum => nil)
89
+ end
90
+
91
+ it "takes a hash as an initialization argument" do
92
+ test_enum = Test::EnumTestMessage.new(:non_default_enum => 2)
93
+ test_enum.non_default_enum.should eq(2)
94
+ end
95
+
96
+ it "initializes with an object that responds to #to_hash" do
97
+ hashie_object = OpenStruct.new(:to_hash => { :non_default_enum => 2 })
98
+ test_enum = Test::EnumTestMessage.new(hashie_object)
99
+ test_enum.non_default_enum.should eq(2)
100
+ end
101
+ end
102
+
103
+ describe '#encode' do
104
+ context "encoding" do
105
+ it "accepts UTF-8 strings into string fields" do
106
+ message = ::Test::Resource.new(:name => "Kyle Redfearn\u0060s iPad")
107
+
108
+ expect { message.encode }.to_not raise_error
109
+ end
110
+
111
+ it "keeps utf-8 when utf-8 is input for string fields" do
112
+ name = "my name\xC3"
113
+ name.force_encoding("UTF-8")
114
+
115
+ message = ::Test::Resource.new(:name => name)
116
+ new_message = ::Test::Resource.decode(message.encode)
117
+ (new_message.name == name).should be_true
118
+ end
119
+
120
+ it "trims binary when binary is input for string fields" do
121
+ name = "my name\xC3"
122
+ name.force_encoding("ASCII-8BIT")
123
+
124
+ message = ::Test::Resource.new(:name => name)
125
+ new_message = ::Test::Resource.decode(message.encode)
126
+ (new_message.name == "my name").should be_true
127
+ end
128
+ end
129
+
130
+ context "when there's no value for a required field" do
131
+ let(:message) { ::Test::ResourceWithRequiredField.new }
132
+
133
+ it "raises a 'message not initialized' error" do
134
+ expect {
135
+ message.encode
136
+ }.to raise_error(Protobuf::SerializationError, /required/i)
137
+ end
138
+ end
139
+
140
+ context "repeated fields" do
141
+ let(:message) { ::Test::Resource.new(:name => "something") }
142
+
143
+ it "does not raise an error when repeated fields are []" do
144
+ expect {
145
+ message.repeated_enum = []
146
+ message.encode
147
+ }.to_not raise_error
148
+ end
149
+
150
+ it "sets the value to nil when empty array is passed" do
151
+ message.repeated_enum = []
152
+ message.instance_variable_get("@values")[:repeated_enum].should be_nil
153
+ end
154
+
155
+ it "does not compact the edit original array" do
156
+ a = [nil].freeze
157
+ message.repeated_enum = a
158
+ message.repeated_enum.should eq([])
159
+ a.should eq([nil].freeze)
160
+ end
161
+
162
+ it "compacts the set array" do
163
+ message.repeated_enum = [nil]
164
+ message.repeated_enum.should eq([])
165
+ end
166
+
167
+ it "raises TypeError when a non-array replaces it" do
168
+ expect {
169
+ message.repeated_enum = 2
170
+ }.to raise_error(/value of type/)
171
+ end
172
+ end
173
+ end
174
+
175
+ describe "boolean predicate methods" do
176
+ subject { Test::ResourceFindRequest.new(:name => "resource") }
177
+
178
+ it { should respond_to(:active?) }
179
+
180
+ it "sets the predicate to true when the boolean value is true" do
181
+ subject.active = true
182
+ subject.active?.should be_true
183
+ end
184
+
185
+ it "sets the predicate to false when the boolean value is false" do
186
+ subject.active = false
187
+ subject.active?.should be_false
188
+ end
189
+
190
+ it "does not put predicate methods on non-boolean fields" do
191
+ Test::ResourceFindRequest.new(:name => "resource").should_not respond_to(:name?)
192
+ end
193
+ end
194
+
195
+ describe "#respond_to_and_has?" do
196
+ subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
197
+
198
+ it "is false when the message does not have the field" do
199
+ subject.respond_to_and_has?(:other_field).should be_false
200
+ end
201
+
202
+ it "is true when the message has the field" do
203
+ subject.respond_to_and_has?(:non_default_enum).should be_true
204
+ end
205
+ end
206
+
207
+ describe "#respond_to_has_and_present?" do
208
+ subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
209
+
210
+ it "is false when the message does not have the field" do
211
+ subject.respond_to_and_has_and_present?(:other_field).should be_false
212
+ end
213
+
214
+ it "is false when the field is repeated and a value is not present" do
215
+ subject.respond_to_and_has_and_present?(:repeated_enums).should be_false
216
+ end
217
+
218
+ it "is false when the field is repeated and the value is empty array" do
219
+ subject.repeated_enums = []
220
+ subject.respond_to_and_has_and_present?(:repeated_enums).should be_false
221
+ end
222
+
223
+ it "is true when the field is repeated and a value is present" do
224
+ subject.repeated_enums = [2]
225
+ subject.respond_to_and_has_and_present?(:repeated_enums).should be_true
226
+ end
227
+
228
+ it "is true when the message has the field" do
229
+ subject.respond_to_and_has_and_present?(:non_default_enum).should be_true
230
+ end
231
+
232
+ context "#API" do
233
+ subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
234
+
235
+ it { should respond_to(:respond_to_and_has_and_present?) }
236
+ it { should respond_to(:responds_to_and_has_and_present?) }
237
+ it { should respond_to(:responds_to_has?) }
238
+ it { should respond_to(:respond_to_has?) }
239
+ it { should respond_to(:respond_to_has_present?) }
240
+ it { should respond_to(:responds_to_has_present?) }
241
+ it { should respond_to(:respond_to_and_has_present?) }
242
+ it { should respond_to(:responds_to_and_has_present?) }
243
+ end
244
+
245
+ end
246
+
247
+ describe '#to_hash' do
248
+ context 'generating values for an ENUM field' do
249
+ it 'converts the enum to its tag representation' do
250
+ hash = Test::EnumTestMessage.new(:non_default_enum => :TWO).to_hash
251
+ hash.should eq({ :non_default_enum => 2 })
252
+ end
253
+
254
+ it 'does not populate default values' do
255
+ hash = Test::EnumTestMessage.new.to_hash
256
+ hash.should eq(Hash.new)
257
+ end
258
+
259
+ it 'converts repeated enum fields to an array of the tags' do
260
+ hash = Test::EnumTestMessage.new(:repeated_enums => [ :ONE, :TWO, :TWO, :ONE ]).to_hash
261
+ hash.should eq({ :repeated_enums => [ 1, 2, 2, 1 ] })
262
+ end
263
+ end
264
+
265
+ context 'generating values for a Message field' do
266
+ it 'recursively hashes field messages' do
267
+ hash = Test::Nested.new({ :resource => { :name => 'Nested' } }).to_hash
268
+ hash.should eq({ :resource => { :name => 'Nested' } })
269
+ end
270
+
271
+ it 'recursively hashes a repeated set of messages' do
272
+ proto = Test::Nested.new(:multiple_resources => [
273
+ Test::Resource.new(:name => 'Resource 1'),
274
+ Test::Resource.new(:name => 'Resource 2')
275
+ ])
276
+
277
+ proto.to_hash.should eq({ :multiple_resources => [ { :name => 'Resource 1' },
278
+ { :name => 'Resource 2' } ] })
279
+
280
+ end
281
+ end
282
+ end
283
+
284
+ describe '#to_json' do
285
+ subject do
286
+ ::Test::ResourceFindRequest.new({ :name => 'Test Name', :active => false })
287
+ end
288
+
289
+ its(:to_json) { should eq '{"name":"Test Name","active":false}' }
290
+ end
291
+
292
+ describe '.to_json' do
293
+ it 'returns the class name of the message for use in json encoding' do
294
+ expect {
295
+ ::Timeout.timeout(0.1) do
296
+ expect(::Test::Resource.to_json).to eq("Test::Resource")
297
+ end
298
+ }.not_to raise_error
299
+ end
300
+ end
301
+
302
+ describe "#define_setter" do
303
+ subject { ::Test::Resource.new }
304
+
305
+ it "allows string fields to be set to nil" do
306
+ expect { subject.name = nil }.to_not raise_error
307
+ end
308
+
309
+ it "does not allow string fields to be set to Numeric" do
310
+ expect { subject.name = 1}.to raise_error(/name/)
311
+ end
312
+ end
313
+
314
+ describe '.get_extension_field' do
315
+ it 'fetches an extension field by its tag' do
316
+ field = ::Test::Resource.get_extension_field(100)
317
+ expect(field).to be_a(::Protobuf::Field::BoolField)
318
+ expect(field.tag).to eq(100)
319
+ expect(field.name).to eq(:ext_is_searchable)
320
+ expect(field).to be_extension
321
+ end
322
+
323
+ it 'fetches an extension field by its symbolized name' do
324
+ expect(::Test::Resource.get_extension_field(:ext_is_searchable)).to be_a(::Protobuf::Field::BoolField)
325
+ expect(::Test::Resource.get_extension_field('ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
326
+ end
327
+
328
+ it 'returns nil when attempting to get a non-extension field' do
329
+ expect(::Test::Resource.get_extension_field(1)).to be_nil
330
+ end
331
+
332
+ it 'returns nil when field is not found' do
333
+ ::Test::Resource.get_extension_field(-1).should be_nil
334
+ ::Test::Resource.get_extension_field(nil).should be_nil
335
+ end
336
+ end
337
+
338
+ describe '.get_field' do
339
+ it 'fetches a non-extension field by its tag' do
340
+ field = ::Test::Resource.get_field(1)
341
+ expect(field).to be_a(::Protobuf::Field::StringField)
342
+ expect(field.tag).to eq(1)
343
+ expect(field.name).to eq(:name)
344
+ expect(field).not_to be_extension
345
+ end
346
+
347
+ it 'fetches a non-extension field by its symbolized name' do
348
+ expect(::Test::Resource.get_field(:name)).to be_a(::Protobuf::Field::StringField)
349
+ expect(::Test::Resource.get_field('name')).to be_a(::Protobuf::Field::StringField)
350
+ end
351
+
352
+ it 'fetches an extension field when forced' do
353
+ expect(::Test::Resource.get_field(100, true)).to be_a(::Protobuf::Field::BoolField)
354
+ expect(::Test::Resource.get_field(:ext_is_searchable, true)).to be_a(::Protobuf::Field::BoolField)
355
+ expect(::Test::Resource.get_field('ext_is_searchable', true)).to be_a(::Protobuf::Field::BoolField)
356
+ end
357
+
358
+ it 'returns nil when attempting to get an extension field' do
359
+ expect(::Test::Resource.get_field(100)).to be_nil
360
+ end
361
+
362
+ it 'returns nil when field is not defined' do
363
+ ::Test::Resource.get_field(-1).should be_nil
364
+ ::Test::Resource.get_field(nil).should be_nil
365
+ end
366
+ end
367
+
368
+ end