protobuffy 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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