protobuffy 3.6.0 → 4.0.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +67 -0
- data/.rubocop_todo.yml +145 -0
- data/.travis.yml +25 -5
- data/CHANGES.md +55 -0
- data/CONTRIBUTING.md +1 -1
- data/LICENSE.txt +17 -9
- data/README.md +13 -12
- data/Rakefile +15 -11
- data/bin/protoc-gen-ruby +8 -3
- data/bin/rpc_server +1 -0
- data/examples/lib/example/reverse-client.rb +2 -2
- data/install-protobuf.sh +28 -0
- data/lib/protobuf.rb +57 -53
- data/lib/protobuf/cli.rb +94 -74
- data/lib/protobuf/code_generator.rb +60 -9
- data/lib/protobuf/decoder.rb +19 -65
- data/lib/protobuf/deprecation.rb +117 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +11 -1
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +55 -3
- data/lib/protobuf/encoder.rb +13 -53
- data/lib/protobuf/enum.rb +58 -63
- data/lib/protobuf/field.rb +4 -4
- data/lib/protobuf/field/base_field.rb +101 -173
- data/lib/protobuf/field/bool_field.rb +17 -11
- data/lib/protobuf/field/bytes_field.rb +21 -35
- data/lib/protobuf/field/double_field.rb +0 -1
- data/lib/protobuf/field/enum_field.rb +23 -22
- data/lib/protobuf/field/field_array.rb +5 -4
- data/lib/protobuf/field/fixed32_field.rb +1 -1
- data/lib/protobuf/field/fixed64_field.rb +0 -1
- data/lib/protobuf/field/float_field.rb +4 -1
- data/lib/protobuf/field/int32_field.rb +0 -1
- data/lib/protobuf/field/int64_field.rb +0 -1
- data/lib/protobuf/field/integer_field.rb +0 -1
- data/lib/protobuf/field/message_field.rb +13 -28
- data/lib/protobuf/field/sfixed32_field.rb +0 -1
- data/lib/protobuf/field/sfixed64_field.rb +0 -1
- data/lib/protobuf/field/signed_integer_field.rb +0 -1
- data/lib/protobuf/field/sint32_field.rb +0 -1
- data/lib/protobuf/field/sint64_field.rb +0 -1
- data/lib/protobuf/field/string_field.rb +2 -4
- data/lib/protobuf/field/uint32_field.rb +0 -1
- data/lib/protobuf/field/uint64_field.rb +0 -1
- data/lib/protobuf/field/varint_field.rb +30 -13
- data/lib/protobuf/generators/base.rb +30 -16
- data/lib/protobuf/generators/enum_generator.rb +6 -9
- data/lib/protobuf/generators/extension_generator.rb +1 -2
- data/lib/protobuf/generators/field_generator.rb +25 -13
- data/lib/protobuf/generators/file_generator.rb +157 -35
- data/lib/protobuf/generators/group_generator.rb +22 -17
- data/lib/protobuf/generators/message_generator.rb +13 -14
- data/lib/protobuf/generators/option_generator.rb +17 -0
- data/lib/protobuf/generators/printable.rb +12 -13
- data/lib/protobuf/generators/service_generator.rb +2 -3
- data/lib/protobuf/http.rb +2 -2
- data/lib/protobuf/lifecycle.rb +20 -33
- data/lib/protobuf/logging.rb +39 -0
- data/lib/protobuf/message.rb +114 -47
- data/lib/protobuf/message/fields.rb +170 -88
- data/lib/protobuf/message/serialization.rb +19 -18
- data/lib/protobuf/optionable.rb +53 -6
- data/lib/protobuf/rpc/buffer.rb +18 -19
- data/lib/protobuf/rpc/client.rb +22 -50
- data/lib/protobuf/rpc/connectors/base.rb +177 -12
- data/lib/protobuf/rpc/connectors/http.rb +14 -9
- data/lib/protobuf/rpc/connectors/ping.rb +89 -0
- data/lib/protobuf/rpc/connectors/socket.rb +13 -8
- data/lib/protobuf/rpc/connectors/zmq.rb +178 -73
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +4 -1
- data/lib/protobuf/rpc/env.rb +12 -12
- data/lib/protobuf/rpc/error.rb +3 -3
- data/lib/protobuf/rpc/error/client_error.rb +4 -4
- data/lib/protobuf/rpc/error/server_error.rb +9 -9
- data/lib/protobuf/rpc/middleware/exception_handler.rb +6 -2
- data/lib/protobuf/rpc/middleware/logger.rb +8 -4
- data/lib/protobuf/rpc/middleware/request_decoder.rb +17 -21
- data/lib/protobuf/rpc/middleware/response_encoder.rb +22 -27
- data/lib/protobuf/rpc/middleware/statsd.rb +3 -3
- data/lib/protobuf/rpc/rpc.pb.rb +4 -1
- data/lib/protobuf/rpc/server.rb +1 -1
- data/lib/protobuf/rpc/servers/http/server.rb +19 -17
- data/lib/protobuf/rpc/servers/socket/server.rb +78 -70
- data/lib/protobuf/rpc/servers/socket/worker.rb +4 -4
- data/lib/protobuf/rpc/servers/socket_runner.rb +27 -15
- data/lib/protobuf/rpc/servers/zmq/broker.rb +70 -31
- data/lib/protobuf/rpc/servers/zmq/server.rb +55 -47
- data/lib/protobuf/rpc/servers/zmq/util.rb +14 -13
- data/lib/protobuf/rpc/servers/zmq/worker.rb +16 -16
- data/lib/protobuf/rpc/servers/zmq_runner.rb +26 -7
- data/lib/protobuf/rpc/service.rb +21 -27
- data/lib/protobuf/rpc/service_directory.rb +43 -27
- data/lib/protobuf/rpc/service_dispatcher.rb +9 -10
- data/lib/protobuf/rpc/service_filters.rb +32 -55
- data/lib/protobuf/rpc/stat.rb +4 -8
- data/lib/protobuf/socket.rb +1 -2
- data/lib/protobuf/tasks/compile.rake +3 -4
- data/lib/protobuf/varint.rb +9 -0
- data/lib/protobuf/varint_pure.rb +13 -0
- data/lib/protobuf/version.rb +1 -1
- data/lib/protobuf/zmq.rb +2 -2
- data/proto/google/protobuf/descriptor.proto +190 -31
- data/protobuffy.gemspec +30 -17
- data/spec/benchmark/tasks.rb +27 -19
- data/spec/bin/protoc-gen-ruby_spec.rb +11 -6
- data/spec/encoding/all_types_spec.rb +96 -84
- data/spec/encoding/extreme_values_spec.rb +0 -0
- data/spec/functional/class_inheritance_spec.rb +52 -0
- data/spec/functional/code_generator_spec.rb +38 -0
- data/spec/functional/socket_server_spec.rb +15 -15
- data/spec/functional/zmq_server_spec.rb +29 -27
- data/spec/lib/protobuf/cli_spec.rb +82 -67
- data/spec/lib/protobuf/code_generator_spec.rb +37 -10
- data/spec/lib/protobuf/enum_spec.rb +77 -46
- data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
- data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/enum_field_spec.rb +26 -0
- data/spec/lib/protobuf/field/field_array_spec.rb +69 -0
- data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
- data/spec/lib/protobuf/field/int32_field_spec.rb +114 -1
- data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
- data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/string_field_spec.rb +44 -11
- data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field_spec.rb +4 -6
- data/spec/lib/protobuf/generators/base_spec.rb +80 -13
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +35 -21
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +12 -13
- data/spec/lib/protobuf/generators/field_generator_spec.rb +73 -21
- data/spec/lib/protobuf/generators/file_generator_spec.rb +89 -6
- data/spec/lib/protobuf/generators/service_generator_spec.rb +25 -13
- data/spec/lib/protobuf/lifecycle_spec.rb +25 -20
- data/spec/lib/protobuf/message_spec.rb +578 -79
- data/spec/lib/protobuf/optionable_spec.rb +202 -26
- data/spec/lib/protobuf/rpc/client_spec.rb +16 -16
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +167 -13
- data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +4 -5
- data/spec/lib/protobuf/rpc/connectors/http_spec.rb +13 -11
- data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +6 -7
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +35 -52
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +10 -10
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +11 -11
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +23 -23
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +11 -11
- data/spec/lib/protobuf/rpc/middleware/statsd_spec.rb +6 -6
- data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +47 -44
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +6 -6
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +12 -10
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +11 -11
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +7 -7
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +47 -49
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +8 -25
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +102 -69
- data/spec/lib/protobuf/rpc/service_spec.rb +37 -36
- data/spec/lib/protobuf/rpc/stat_spec.rb +7 -9
- data/spec/lib/protobuf/varint_spec.rb +29 -0
- data/spec/lib/protobuf_spec.rb +55 -28
- data/spec/spec_helper.rb +12 -27
- data/spec/support/all.rb +0 -1
- data/spec/support/packed_field.rb +4 -3
- data/spec/support/{test → protos}/all_types.data.bin +0 -0
- data/spec/support/{test → protos}/all_types.data.txt +0 -0
- data/spec/support/{test → protos}/enum.pb.rb +8 -4
- data/spec/support/{test → protos}/enum.proto +4 -1
- data/spec/support/{test → protos}/extreme_values.data.bin +0 -0
- data/spec/support/protos/google_unittest.bin +0 -0
- data/spec/support/protos/google_unittest.pb.rb +798 -0
- data/spec/support/{test → protos}/google_unittest.proto +237 -66
- data/spec/support/protos/google_unittest_custom_options.bin +0 -0
- data/spec/support/protos/google_unittest_custom_options.pb.rb +268 -0
- data/spec/support/protos/google_unittest_custom_options.proto +424 -0
- data/spec/support/protos/google_unittest_import.pb.rb +55 -0
- data/spec/support/{test → protos}/google_unittest_import.proto +19 -10
- data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
- data/spec/support/{test → protos}/google_unittest_import_public.proto +8 -5
- data/spec/support/{test → protos}/multi_field_extensions.pb.rb +5 -2
- data/spec/support/{test → protos}/multi_field_extensions.proto +2 -0
- data/spec/support/{test → protos}/resource.pb.rb +47 -11
- data/spec/support/{test → protos}/resource.proto +24 -1
- data/spec/support/resource_service.rb +23 -0
- data/spec/support/server.rb +32 -61
- metadata +119 -59
- data/lib/protobuf/deprecator.rb +0 -42
- data/lib/protobuf/logger.rb +0 -93
- data/lib/protobuf/rpc/connector.rb +0 -21
- data/lib/protobuf/rpc/connectors/common.rb +0 -172
- data/spec/data/data.bin +0 -3
- data/spec/data/types.bin +0 -0
- data/spec/lib/protobuf/logger_spec.rb +0 -145
- data/spec/lib/protobuf/rpc/connector_spec.rb +0 -26
- data/spec/lib/protobuf/rpc/connectors/common_spec.rb +0 -170
- data/spec/support/test/defaults.pb.rb +0 -25
- data/spec/support/test/defaults.proto +0 -9
- data/spec/support/test/extended.pb.rb +0 -22
- data/spec/support/test/extended.proto +0 -10
- data/spec/support/test/google_unittest.pb.rb +0 -543
- data/spec/support/test/google_unittest_import.pb.rb +0 -37
- data/spec/support/test/google_unittest_import_public.pb.rb +0 -8
- data/spec/support/test/resource_service.rb +0 -26
- data/spec/support/tolerance_matcher.rb +0 -40
@@ -2,28 +2,111 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
require 'protobuf/generators/file_generator'
|
4
4
|
|
5
|
-
describe ::Protobuf::Generators::FileGenerator do
|
5
|
+
RSpec.describe ::Protobuf::Generators::FileGenerator do
|
6
6
|
|
7
7
|
let(:base_descriptor_fields) { { :name => 'test/foo.proto' } }
|
8
8
|
let(:descriptor_fields) { base_descriptor_fields }
|
9
9
|
let(:file_descriptor) { ::Google::Protobuf::FileDescriptorProto.new(descriptor_fields) }
|
10
10
|
|
11
11
|
subject { described_class.new(file_descriptor) }
|
12
|
-
|
12
|
+
specify { expect(subject.file_name).to eq('test/foo.pb.rb') }
|
13
13
|
|
14
14
|
describe '#print_import_requires' do
|
15
15
|
let(:descriptor_fields) do
|
16
|
-
base_descriptor_fields.merge
|
17
|
-
|
16
|
+
base_descriptor_fields.merge(
|
17
|
+
:dependency => [
|
18
|
+
'test/bar.proto',
|
19
|
+
'test/baz.proto',
|
20
|
+
]
|
21
|
+
)
|
18
22
|
end
|
19
23
|
|
20
24
|
it 'prints a ruby require for each dependency' do
|
21
|
-
subject.
|
22
|
-
subject.
|
25
|
+
expect(subject).to receive(:print_require).with('test/bar.pb')
|
26
|
+
expect(subject).to receive(:print_require).with('test/baz.pb')
|
23
27
|
subject.print_import_requires
|
24
28
|
end
|
25
29
|
|
26
30
|
end
|
27
31
|
|
32
|
+
describe '#compile' do
|
33
|
+
it 'generates the file contents' do
|
34
|
+
subject.compile
|
35
|
+
expect(subject.to_s).to eq <<EOF
|
36
|
+
# encoding: utf-8
|
37
|
+
|
38
|
+
##
|
39
|
+
# This file is auto-generated. DO NOT EDIT!
|
40
|
+
#
|
41
|
+
require 'protobuf'
|
42
|
+
|
43
|
+
EOF
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'generates the file contents using default package name' do
|
47
|
+
allow(ENV).to receive(:key?).with('PB_ALLOW_DEFAULT_PACKAGE_NAME')
|
48
|
+
.and_return(true)
|
49
|
+
subject.compile
|
50
|
+
expect(subject.to_s).to eq <<EOF
|
51
|
+
# encoding: utf-8
|
52
|
+
|
53
|
+
##
|
54
|
+
# This file is auto-generated. DO NOT EDIT!
|
55
|
+
#
|
56
|
+
require 'protobuf'
|
57
|
+
|
58
|
+
module Foo
|
59
|
+
::Protobuf::Optionable.inject(self) { ::Google::Protobuf::FileOptions }
|
28
60
|
end
|
29
61
|
|
62
|
+
EOF
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with extended messages' do
|
66
|
+
let(:descriptor_fields) do
|
67
|
+
base_descriptor_fields.merge(
|
68
|
+
:package => 'test.pkg.file_generator_spec',
|
69
|
+
:extension => [{
|
70
|
+
:name => 'boom',
|
71
|
+
:number => 20_000,
|
72
|
+
:label => Google::Protobuf::FieldDescriptorProto::Label::LABEL_OPTIONAL,
|
73
|
+
:type => Google::Protobuf::FieldDescriptorProto::Type::TYPE_STRING,
|
74
|
+
:extendee => '.google.protobuf.FieldOptions',
|
75
|
+
}]
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'generates the file contents that include the namespaced extension name' do
|
80
|
+
subject.compile
|
81
|
+
expect(subject.to_s).to eq <<EOF
|
82
|
+
# encoding: utf-8
|
83
|
+
|
84
|
+
##
|
85
|
+
# This file is auto-generated. DO NOT EDIT!
|
86
|
+
#
|
87
|
+
require 'protobuf'
|
88
|
+
|
89
|
+
module Test
|
90
|
+
module Pkg
|
91
|
+
module File_generator_spec
|
92
|
+
::Protobuf::Optionable.inject(self) { ::Google::Protobuf::FileOptions }
|
93
|
+
|
94
|
+
##
|
95
|
+
# Extended Message Fields
|
96
|
+
#
|
97
|
+
class ::Google::Protobuf::FieldOptions < ::Protobuf::Message
|
98
|
+
optional :string, :".test.pkg.file_generator_spec.boom", 20000, :extension => true
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
EOF
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -2,42 +2,54 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
require 'protobuf/generators/service_generator'
|
4
4
|
|
5
|
-
describe ::Protobuf::Generators::ServiceGenerator do
|
5
|
+
RSpec.describe ::Protobuf::Generators::ServiceGenerator do
|
6
6
|
|
7
|
-
let(:methods)
|
7
|
+
let(:methods) do
|
8
8
|
[
|
9
9
|
{ :name => 'Search', :input_type => 'FooRequest', :output_type => 'FooResponse' },
|
10
|
-
{ :name => 'FooBar', :input_type => '.foo.Request', :output_type => '.bar.Response' }
|
10
|
+
{ :name => 'FooBar', :input_type => '.foo.Request', :output_type => '.bar.Response' },
|
11
11
|
]
|
12
|
-
|
13
|
-
let(:service_fields)
|
14
|
-
|
12
|
+
end
|
13
|
+
let(:service_fields) do
|
14
|
+
{
|
15
|
+
:name => 'TestService',
|
16
|
+
:method => methods,
|
17
|
+
}
|
18
|
+
end
|
15
19
|
|
16
20
|
let(:service) { ::Google::Protobuf::ServiceDescriptorProto.new(service_fields) }
|
17
21
|
|
18
22
|
subject { described_class.new(service) }
|
19
23
|
|
20
24
|
describe '#compile' do
|
21
|
-
let(:compiled)
|
22
|
-
|
25
|
+
let(:compiled) do
|
26
|
+
'class TestService < ::Protobuf::Rpc::Service
|
23
27
|
rpc :search, FooRequest, FooResponse
|
24
28
|
rpc :foo_bar, ::Foo::Request, ::Bar::Response
|
25
29
|
end
|
26
30
|
|
27
|
-
|
28
|
-
|
31
|
+
'
|
32
|
+
end
|
29
33
|
|
30
34
|
it 'compiles the service and it\'s rpc methods' do
|
31
35
|
subject.compile
|
32
|
-
subject.to_s.
|
36
|
+
expect(subject.to_s).to eq(compiled)
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
36
40
|
describe '#build_method' do
|
37
41
|
it 'returns a string identifying the given method descriptor' do
|
38
|
-
subject.build_method(service.method.first).
|
42
|
+
expect(subject.build_method(service.method.first)).to eq("rpc :search, FooRequest, FooResponse")
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with PB_USE_RAW_RPC_NAMES in the environemnt' do
|
46
|
+
before { allow(ENV).to receive(:key?).with('PB_USE_RAW_RPC_NAMES').and_return(true) }
|
47
|
+
|
48
|
+
it 'uses the raw RPC name and does not underscore it' do
|
49
|
+
expect(subject.build_method(service.method.first)).to eq("rpc :Search, FooRequest, FooResponse")
|
50
|
+
expect(subject.build_method(service.method.last)).to eq("rpc :FooBar, ::Foo::Request, ::Bar::Response")
|
51
|
+
end
|
39
52
|
end
|
40
53
|
end
|
41
54
|
|
42
55
|
end
|
43
|
-
|
@@ -1,22 +1,27 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'protobuf/lifecycle'
|
3
3
|
|
4
|
-
describe ::Protobuf::Lifecycle do
|
4
|
+
RSpec.describe ::Protobuf::Lifecycle do
|
5
5
|
subject { described_class }
|
6
6
|
|
7
|
-
|
7
|
+
around do |example|
|
8
|
+
# this entire class is deprecated
|
9
|
+
::Protobuf.deprecator.silence(&example)
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
8
13
|
::ActiveSupport::Notifications.notifier = ::ActiveSupport::Notifications::Fanout.new
|
9
14
|
end
|
10
15
|
|
11
16
|
it "registers a string as the event_name" do
|
12
|
-
::ActiveSupport::Notifications.
|
13
|
-
|
17
|
+
expect(::ActiveSupport::Notifications).to receive(:subscribe).with("something")
|
18
|
+
subject.register("something") { true }
|
14
19
|
end
|
15
20
|
|
16
21
|
it "only registers blocks for event callbacks" do
|
17
|
-
expect
|
22
|
+
expect do
|
18
23
|
subject.register("something")
|
19
|
-
|
24
|
+
end.to raise_error(/block/)
|
20
25
|
end
|
21
26
|
|
22
27
|
it "calls the registered block when triggered" do
|
@@ -26,8 +31,8 @@ describe ::Protobuf::Lifecycle do
|
|
26
31
|
end
|
27
32
|
|
28
33
|
subject.trigger("this")
|
29
|
-
this.
|
30
|
-
this.
|
34
|
+
expect(this).to_not be_nil
|
35
|
+
expect(this).to eq("not nil")
|
31
36
|
end
|
32
37
|
|
33
38
|
it "calls multiple registered blocks when triggered" do
|
@@ -43,10 +48,10 @@ describe ::Protobuf::Lifecycle do
|
|
43
48
|
end
|
44
49
|
|
45
50
|
subject.trigger("this")
|
46
|
-
this.
|
47
|
-
this.
|
48
|
-
that.
|
49
|
-
that.
|
51
|
+
expect(this).to_not be_nil
|
52
|
+
expect(this).to eq("not nil")
|
53
|
+
expect(that).to_not be_nil
|
54
|
+
expect(that).to eq("not nil")
|
50
55
|
end
|
51
56
|
|
52
57
|
context 'when the registered block has arity' do
|
@@ -55,12 +60,12 @@ describe ::Protobuf::Lifecycle do
|
|
55
60
|
outer_bar = nil
|
56
61
|
|
57
62
|
subject.register('foo') do |bar|
|
58
|
-
bar.
|
63
|
+
expect(bar).to be_nil
|
59
64
|
outer_bar = 'triggered'
|
60
65
|
end
|
61
66
|
|
62
67
|
subject.trigger('foo')
|
63
|
-
outer_bar.
|
68
|
+
expect(outer_bar).to eq 'triggered'
|
64
69
|
end
|
65
70
|
end
|
66
71
|
|
@@ -69,21 +74,21 @@ describe ::Protobuf::Lifecycle do
|
|
69
74
|
outer_bar = nil
|
70
75
|
|
71
76
|
subject.register('foo') do |bar|
|
72
|
-
bar.
|
77
|
+
expect(bar).to_not be_nil
|
73
78
|
outer_bar = bar
|
74
79
|
end
|
75
80
|
|
76
81
|
subject.trigger('foo', 'baz')
|
77
|
-
outer_bar.
|
82
|
+
expect(outer_bar).to eq 'baz'
|
78
83
|
end
|
79
84
|
end
|
80
85
|
end
|
81
86
|
|
82
87
|
context "normalized event names" do
|
83
|
-
specify { subject.normalized_event_name(:derp).
|
84
|
-
specify { subject.normalized_event_name(:Derp).
|
85
|
-
specify { subject.normalized_event_name("DERP").
|
86
|
-
specify { subject.normalized_event_name("derp").
|
88
|
+
specify { expect(subject.normalized_event_name(:derp)).to eq("derp") }
|
89
|
+
specify { expect(subject.normalized_event_name(:Derp)).to eq("derp") }
|
90
|
+
specify { expect(subject.normalized_event_name("DERP")).to eq("derp") }
|
91
|
+
specify { expect(subject.normalized_event_name("derp")).to eq("derp") }
|
87
92
|
end
|
88
93
|
|
89
94
|
end
|
@@ -1,59 +1,132 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'stringio'
|
1
4
|
require 'spec_helper'
|
5
|
+
require PROTOS_PATH.join('resource.pb')
|
6
|
+
require PROTOS_PATH.join('enum.pb')
|
2
7
|
|
3
|
-
describe Protobuf::Message do
|
8
|
+
RSpec.describe Protobuf::Message do
|
4
9
|
|
5
10
|
describe '.decode' do
|
6
11
|
let(:message) { ::Test::Resource.new(:name => "Jim") }
|
7
12
|
|
8
13
|
it 'creates a new message object decoded from the given bytes' do
|
9
|
-
::Test::Resource.decode(message.encode).
|
14
|
+
expect(::Test::Resource.decode(message.encode)).to eq message
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with a new enum value' do
|
18
|
+
let(:older_message) do
|
19
|
+
Class.new(Protobuf::Message) do
|
20
|
+
enum_class = Class.new(::Protobuf::Enum) do
|
21
|
+
define :YAY, 1
|
22
|
+
end
|
23
|
+
|
24
|
+
optional enum_class, :enum_field, 1
|
25
|
+
repeated enum_class, :enum_list, 2
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:newer_message) do
|
30
|
+
Class.new(Protobuf::Message) do
|
31
|
+
enum_class = Class.new(::Protobuf::Enum) do
|
32
|
+
define :YAY, 1
|
33
|
+
define :HOORAY, 2
|
34
|
+
end
|
35
|
+
|
36
|
+
optional enum_class, :enum_field, 1
|
37
|
+
repeated enum_class, :enum_list, 2
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with a singular field' do
|
42
|
+
it 'treats the field as if it was unset when decoding' do
|
43
|
+
newer = newer_message.new(:enum_field => :HOORAY).serialize
|
44
|
+
|
45
|
+
expect(older_message.decode(newer).enum_field!).to be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'rejects an unknown value when using the constructor' do
|
49
|
+
expect { older_message.new(:enum_field => :HOORAY) }.to raise_error(TypeError)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'rejects an unknown value when the setter' do
|
53
|
+
older = older_message.new
|
54
|
+
expect { older.enum_field = :HOORAY }.to raise_error(TypeError)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with a repeated field' do
|
59
|
+
it 'treats the field as if it was unset when decoding' do
|
60
|
+
newer = newer_message.new(:enum_list => [:HOORAY]).serialize
|
61
|
+
|
62
|
+
expect(older_message.decode(newer).enum_list).to eq([])
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'rejects an unknown value when using the constructor' do
|
66
|
+
expect { older_message.new(:enum_list => [:HOORAY]) }.to raise_error(TypeError)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'rejects an unknown value when the setter' do
|
70
|
+
older = older_message.new
|
71
|
+
expect { older.enum_field = [:HOORAY] }.to raise_error(TypeError)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '.decode_from' do
|
78
|
+
let(:message) { ::Test::Resource.new(:name => "Jim") }
|
79
|
+
|
80
|
+
it 'creates a new message object decoded from the given byte stream' do
|
81
|
+
stream = ::StringIO.new(message.encode)
|
82
|
+
expect(::Test::Resource.decode_from(stream)).to eq message
|
10
83
|
end
|
11
84
|
end
|
12
85
|
|
13
86
|
describe 'defining a new field' do
|
14
87
|
context 'when defining a field with a tag that has already been used' do
|
15
88
|
it 'raises a TagCollisionError' do
|
16
|
-
expect
|
89
|
+
expect do
|
17
90
|
Class.new(Protobuf::Message) do
|
18
91
|
optional ::Protobuf::Field::Int32Field, :foo, 1
|
19
92
|
optional ::Protobuf::Field::Int32Field, :bar, 1
|
20
93
|
end
|
21
|
-
|
94
|
+
end.to raise_error(Protobuf::TagCollisionError, /Field number 1 has already been used/)
|
22
95
|
end
|
23
96
|
end
|
24
97
|
|
25
98
|
context 'when defining an extension field with a tag that has already been used' do
|
26
99
|
it 'raises a TagCollisionError' do
|
27
|
-
expect
|
100
|
+
expect do
|
28
101
|
Class.new(Protobuf::Message) do
|
29
102
|
extensions 100...110
|
30
103
|
optional ::Protobuf::Field::Int32Field, :foo, 100
|
31
104
|
optional ::Protobuf::Field::Int32Field, :bar, 100, :extension => true
|
32
105
|
end
|
33
|
-
|
106
|
+
end.to raise_error(Protobuf::TagCollisionError, /Field number 100 has already been used/)
|
34
107
|
end
|
35
108
|
end
|
36
109
|
|
37
110
|
context 'when defining a field with a name that has already been used' do
|
38
111
|
it 'raises a DuplicateFieldNameError' do
|
39
|
-
expect
|
112
|
+
expect do
|
40
113
|
Class.new(Protobuf::Message) do
|
41
114
|
optional ::Protobuf::Field::Int32Field, :foo, 1
|
42
115
|
optional ::Protobuf::Field::Int32Field, :foo, 2
|
43
116
|
end
|
44
|
-
|
117
|
+
end.to raise_error(Protobuf::DuplicateFieldNameError, /Field name foo has already been used/)
|
45
118
|
end
|
46
119
|
end
|
47
120
|
|
48
121
|
context 'when defining an extension field with a name that has already been used' do
|
49
122
|
it 'raises a DuplicateFieldNameError' do
|
50
|
-
expect
|
123
|
+
expect do
|
51
124
|
Class.new(Protobuf::Message) do
|
52
125
|
extensions 100...110
|
53
126
|
optional ::Protobuf::Field::Int32Field, :foo, 1
|
54
127
|
optional ::Protobuf::Field::Int32Field, :foo, 100, :extension => true
|
55
128
|
end
|
56
|
-
|
129
|
+
end.to raise_error(Protobuf::DuplicateFieldNameError, /Field name foo has already been used/)
|
57
130
|
end
|
58
131
|
end
|
59
132
|
end
|
@@ -62,41 +135,57 @@ describe Protobuf::Message do
|
|
62
135
|
let(:values) { { :name => "Jim" } }
|
63
136
|
|
64
137
|
it 'creates a new message object with the given values and returns the encoded bytes' do
|
65
|
-
::Test::Resource.encode(values).
|
138
|
+
expect(::Test::Resource.encode(values)).to eq ::Test::Resource.new(values).encode
|
66
139
|
end
|
67
140
|
end
|
68
141
|
|
69
142
|
describe '#initialize' do
|
70
|
-
it "
|
143
|
+
it "defaults to the first value listed in the enum's type definition" do
|
144
|
+
test_enum = Test::EnumTestMessage.new
|
145
|
+
expect(test_enum.non_default_enum).to eq(Test::EnumTestType.enums.first)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "defaults to a a value with a name" do
|
71
149
|
test_enum = Test::EnumTestMessage.new
|
72
|
-
test_enum.non_default_enum.
|
150
|
+
expect(test_enum.non_default_enum.name).to eq(Test::EnumTestType.enums.first.name)
|
73
151
|
end
|
74
152
|
|
75
153
|
it "exposes the enum getter raw value through ! method" do
|
76
154
|
test_enum = Test::EnumTestMessage.new
|
77
|
-
test_enum.non_default_enum
|
155
|
+
expect(test_enum.non_default_enum!).to be_nil
|
78
156
|
end
|
79
157
|
|
80
158
|
it "exposes the enum getter raw value through ! method (when set)" do
|
81
159
|
test_enum = Test::EnumTestMessage.new
|
82
160
|
test_enum.non_default_enum = 1
|
83
|
-
test_enum.non_default_enum
|
161
|
+
expect(test_enum.non_default_enum!).to eq(1)
|
84
162
|
end
|
85
163
|
|
86
164
|
it "does not try to set attributes which have nil values" do
|
87
|
-
Test::EnumTestMessage.
|
165
|
+
expect_any_instance_of(Test::EnumTestMessage).not_to receive("non_default_enum=")
|
88
166
|
Test::EnumTestMessage.new(:non_default_enum => nil)
|
89
167
|
end
|
90
168
|
|
91
169
|
it "takes a hash as an initialization argument" do
|
92
170
|
test_enum = Test::EnumTestMessage.new(:non_default_enum => 2)
|
93
|
-
test_enum.non_default_enum.
|
171
|
+
expect(test_enum.non_default_enum).to eq(2)
|
94
172
|
end
|
95
173
|
|
96
174
|
it "initializes with an object that responds to #to_hash" do
|
97
175
|
hashie_object = OpenStruct.new(:to_hash => { :non_default_enum => 2 })
|
98
176
|
test_enum = Test::EnumTestMessage.new(hashie_object)
|
99
|
-
test_enum.non_default_enum.
|
177
|
+
expect(test_enum.non_default_enum).to eq(2)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "initializes with an object with a block" do
|
181
|
+
test_enum = Test::EnumTestMessage.new { |p| p.non_default_enum = 2 }
|
182
|
+
expect(test_enum.non_default_enum).to eq(2)
|
183
|
+
end
|
184
|
+
|
185
|
+
# to be deprecated
|
186
|
+
it "allows you to pass nil to repeated fields" do
|
187
|
+
test = Test::Resource.new(:repeated_enum => nil)
|
188
|
+
expect(test.repeated_enum).to eq([])
|
100
189
|
end
|
101
190
|
end
|
102
191
|
|
@@ -109,21 +198,21 @@ describe Protobuf::Message do
|
|
109
198
|
end
|
110
199
|
|
111
200
|
it "keeps utf-8 when utf-8 is input for string fields" do
|
112
|
-
name =
|
113
|
-
name.force_encoding(
|
201
|
+
name = 'my name💩'
|
202
|
+
name.force_encoding(Encoding::UTF_8)
|
114
203
|
|
115
204
|
message = ::Test::Resource.new(:name => name)
|
116
205
|
new_message = ::Test::Resource.decode(message.encode)
|
117
|
-
(new_message.name == name).
|
206
|
+
expect(new_message.name == name).to be true
|
118
207
|
end
|
119
208
|
|
120
209
|
it "trims binary when binary is input for string fields" do
|
121
210
|
name = "my name\xC3"
|
122
|
-
name.force_encoding(
|
211
|
+
name.force_encoding(Encoding::BINARY)
|
123
212
|
|
124
213
|
message = ::Test::Resource.new(:name => name)
|
125
214
|
new_message = ::Test::Resource.decode(message.encode)
|
126
|
-
(new_message.name == "my name").
|
215
|
+
expect(new_message.name == "my name").to be true
|
127
216
|
end
|
128
217
|
end
|
129
218
|
|
@@ -131,9 +220,9 @@ describe Protobuf::Message do
|
|
131
220
|
let(:message) { ::Test::ResourceWithRequiredField.new }
|
132
221
|
|
133
222
|
it "raises a 'message not initialized' error" do
|
134
|
-
expect
|
223
|
+
expect do
|
135
224
|
message.encode
|
136
|
-
|
225
|
+
end.to raise_error(Protobuf::SerializationError, /required/i)
|
137
226
|
end
|
138
227
|
end
|
139
228
|
|
@@ -141,33 +230,33 @@ describe Protobuf::Message do
|
|
141
230
|
let(:message) { ::Test::Resource.new(:name => "something") }
|
142
231
|
|
143
232
|
it "does not raise an error when repeated fields are []" do
|
144
|
-
expect
|
233
|
+
expect do
|
145
234
|
message.repeated_enum = []
|
146
235
|
message.encode
|
147
|
-
|
236
|
+
end.to_not raise_error
|
148
237
|
end
|
149
238
|
|
150
239
|
it "sets the value to nil when empty array is passed" do
|
151
240
|
message.repeated_enum = []
|
152
|
-
message.instance_variable_get("@values")[:repeated_enum].
|
241
|
+
expect(message.instance_variable_get("@values")[:repeated_enum]).to be_nil
|
153
242
|
end
|
154
243
|
|
155
244
|
it "does not compact the edit original array" do
|
156
245
|
a = [nil].freeze
|
157
246
|
message.repeated_enum = a
|
158
|
-
message.repeated_enum.
|
159
|
-
a.
|
247
|
+
expect(message.repeated_enum).to eq([])
|
248
|
+
expect(a).to eq([nil].freeze)
|
160
249
|
end
|
161
250
|
|
162
251
|
it "compacts the set array" do
|
163
252
|
message.repeated_enum = [nil]
|
164
|
-
message.repeated_enum.
|
253
|
+
expect(message.repeated_enum).to eq([])
|
165
254
|
end
|
166
255
|
|
167
256
|
it "raises TypeError when a non-array replaces it" do
|
168
|
-
expect
|
257
|
+
expect do
|
169
258
|
message.repeated_enum = 2
|
170
|
-
|
259
|
+
end.to raise_error(/value of type/)
|
171
260
|
end
|
172
261
|
end
|
173
262
|
end
|
@@ -175,20 +264,20 @@ describe Protobuf::Message do
|
|
175
264
|
describe "boolean predicate methods" do
|
176
265
|
subject { Test::ResourceFindRequest.new(:name => "resource") }
|
177
266
|
|
178
|
-
it {
|
267
|
+
it { is_expected.to respond_to(:active?) }
|
179
268
|
|
180
269
|
it "sets the predicate to true when the boolean value is true" do
|
181
270
|
subject.active = true
|
182
|
-
subject.active
|
271
|
+
expect(subject.active?).to be true
|
183
272
|
end
|
184
273
|
|
185
274
|
it "sets the predicate to false when the boolean value is false" do
|
186
275
|
subject.active = false
|
187
|
-
subject.active
|
276
|
+
expect(subject.active?).to be false
|
188
277
|
end
|
189
278
|
|
190
279
|
it "does not put predicate methods on non-boolean fields" do
|
191
|
-
Test::ResourceFindRequest.new(:name => "resource").
|
280
|
+
expect(Test::ResourceFindRequest.new(:name => "resource")).to_not respond_to(:name?)
|
192
281
|
end
|
193
282
|
end
|
194
283
|
|
@@ -196,11 +285,11 @@ describe Protobuf::Message do
|
|
196
285
|
subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
|
197
286
|
|
198
287
|
it "is false when the message does not have the field" do
|
199
|
-
subject.respond_to_and_has?(:other_field).
|
288
|
+
expect(subject.respond_to_and_has?(:other_field)).to be false
|
200
289
|
end
|
201
290
|
|
202
291
|
it "is true when the message has the field" do
|
203
|
-
subject.respond_to_and_has?(:non_default_enum).
|
292
|
+
expect(subject.respond_to_and_has?(:non_default_enum)).to be true
|
204
293
|
end
|
205
294
|
end
|
206
295
|
|
@@ -208,106 +297,204 @@ describe Protobuf::Message do
|
|
208
297
|
subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
|
209
298
|
|
210
299
|
it "is false when the message does not have the field" do
|
211
|
-
subject.respond_to_and_has_and_present?(:other_field).
|
300
|
+
expect(subject.respond_to_and_has_and_present?(:other_field)).to be false
|
212
301
|
end
|
213
302
|
|
214
303
|
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).
|
304
|
+
expect(subject.respond_to_and_has_and_present?(:repeated_enums)).to be false
|
216
305
|
end
|
217
306
|
|
218
307
|
it "is false when the field is repeated and the value is empty array" do
|
219
308
|
subject.repeated_enums = []
|
220
|
-
subject.respond_to_and_has_and_present?(:repeated_enums).
|
309
|
+
expect(subject.respond_to_and_has_and_present?(:repeated_enums)).to be false
|
221
310
|
end
|
222
311
|
|
223
312
|
it "is true when the field is repeated and a value is present" do
|
224
313
|
subject.repeated_enums = [2]
|
225
|
-
subject.respond_to_and_has_and_present?(:repeated_enums).
|
314
|
+
expect(subject.respond_to_and_has_and_present?(:repeated_enums)).to be true
|
226
315
|
end
|
227
316
|
|
228
317
|
it "is true when the message has the field" do
|
229
|
-
subject.respond_to_and_has_and_present?(:non_default_enum).
|
318
|
+
expect(subject.respond_to_and_has_and_present?(:non_default_enum)).to be true
|
230
319
|
end
|
231
320
|
|
232
321
|
context "#API" do
|
233
322
|
subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
|
234
323
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
324
|
+
specify { expect(subject).to respond_to(:respond_to_and_has_and_present?) }
|
325
|
+
specify { expect(subject).to respond_to(:responds_to_and_has_and_present?) }
|
326
|
+
specify { expect(subject).to respond_to(:responds_to_has?) }
|
327
|
+
specify { expect(subject).to respond_to(:respond_to_has?) }
|
328
|
+
specify { expect(subject).to respond_to(:respond_to_has_present?) }
|
329
|
+
specify { expect(subject).to respond_to(:responds_to_has_present?) }
|
330
|
+
specify { expect(subject).to respond_to(:respond_to_and_has_present?) }
|
331
|
+
specify { expect(subject).to respond_to(:responds_to_and_has_present?) }
|
243
332
|
end
|
244
333
|
|
245
334
|
end
|
246
335
|
|
336
|
+
describe '#inspect' do
|
337
|
+
let(:klass) do
|
338
|
+
Class.new(Protobuf::Message) do |klass|
|
339
|
+
enum_class = Class.new(Protobuf::Enum) do
|
340
|
+
define :YAY, 1
|
341
|
+
end
|
342
|
+
|
343
|
+
klass.const_set(:EnumKlass, enum_class)
|
344
|
+
|
345
|
+
optional :string, :name, 1
|
346
|
+
repeated :int32, :counts, 2
|
347
|
+
optional enum_class, :enum, 3
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
before { stub_const('MyMessage', klass) }
|
352
|
+
|
353
|
+
it 'lists the fields' do
|
354
|
+
proto = klass.new(:name => 'wooo', :counts => [1, 2, 3], :enum => klass::EnumKlass::YAY)
|
355
|
+
expect(proto.inspect).to eq('#<MyMessage name="wooo" counts=[1, 2, 3] enum=#<Protobuf::Enum(MyMessage::EnumKlass)::YAY=1>>')
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
247
359
|
describe '#to_hash' do
|
248
360
|
context 'generating values for an ENUM field' do
|
249
361
|
it 'converts the enum to its tag representation' do
|
250
362
|
hash = Test::EnumTestMessage.new(:non_default_enum => :TWO).to_hash
|
251
|
-
hash.
|
363
|
+
expect(hash).to eq(:non_default_enum => 2)
|
252
364
|
end
|
253
365
|
|
254
366
|
it 'does not populate default values' do
|
255
367
|
hash = Test::EnumTestMessage.new.to_hash
|
256
|
-
hash.
|
368
|
+
expect(hash).to eq({})
|
257
369
|
end
|
258
370
|
|
259
371
|
it 'converts repeated enum fields to an array of the tags' do
|
260
|
-
hash = Test::EnumTestMessage.new(:repeated_enums => [
|
261
|
-
hash.
|
372
|
+
hash = Test::EnumTestMessage.new(:repeated_enums => [:ONE, :TWO, :TWO, :ONE]).to_hash
|
373
|
+
expect(hash).to eq(:repeated_enums => [1, 2, 2, 1])
|
262
374
|
end
|
263
375
|
end
|
264
376
|
|
265
377
|
context 'generating values for a Message field' do
|
266
378
|
it 'recursively hashes field messages' do
|
267
|
-
hash = Test::Nested.new(
|
268
|
-
hash.
|
379
|
+
hash = Test::Nested.new(:resource => { :name => 'Nested' }).to_hash
|
380
|
+
expect(hash).to eq(:resource => { :name => 'Nested' })
|
269
381
|
end
|
270
382
|
|
271
383
|
it 'recursively hashes a repeated set of messages' do
|
272
|
-
proto = Test::Nested.new(
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
384
|
+
proto = Test::Nested.new(
|
385
|
+
:multiple_resources => [
|
386
|
+
Test::Resource.new(:name => 'Resource 1'),
|
387
|
+
Test::Resource.new(:name => 'Resource 2'),
|
388
|
+
]
|
389
|
+
)
|
390
|
+
|
391
|
+
expect(proto.to_hash).to eq(
|
392
|
+
:multiple_resources => [
|
393
|
+
{ :name => 'Resource 1' },
|
394
|
+
{ :name => 'Resource 2' },
|
395
|
+
]
|
396
|
+
)
|
397
|
+
end
|
398
|
+
end
|
279
399
|
|
400
|
+
it 'uses simple field names as keys when possible and fully qualified names otherwise' do
|
401
|
+
message = Class.new(::Protobuf::Message) do
|
402
|
+
optional :int32, :field, 1
|
403
|
+
optional :int32, :colliding_field, 2
|
404
|
+
extensions 100...200
|
405
|
+
optional :int32, :".ext.normal_ext_field", 100, :extension => true
|
406
|
+
optional :int32, :".ext.colliding_field", 101, :extension => true
|
407
|
+
optional :int32, :".ext.colliding_field2", 102, :extension => true
|
408
|
+
optional :int32, :".ext2.colliding_field2", 103, :extension => true
|
280
409
|
end
|
410
|
+
|
411
|
+
hash = {
|
412
|
+
:field => 1,
|
413
|
+
:colliding_field => 2,
|
414
|
+
:normal_ext_field => 3,
|
415
|
+
:".ext.colliding_field" => 4,
|
416
|
+
:".ext.colliding_field2" => 5,
|
417
|
+
:".ext2.colliding_field2" => 6,
|
418
|
+
}
|
419
|
+
instance = message.new(hash)
|
420
|
+
expect(instance.to_hash).to eq(hash)
|
281
421
|
end
|
282
422
|
end
|
283
423
|
|
284
424
|
describe '#to_json' do
|
285
425
|
subject do
|
286
|
-
::Test::ResourceFindRequest.new(
|
426
|
+
::Test::ResourceFindRequest.new(:name => 'Test Name', :active => false)
|
287
427
|
end
|
288
428
|
|
289
|
-
|
429
|
+
specify { expect(subject.to_json).to eq '{"name":"Test Name","active":false}' }
|
290
430
|
end
|
291
431
|
|
292
432
|
describe '.to_json' do
|
293
433
|
it 'returns the class name of the message for use in json encoding' do
|
294
|
-
expect
|
434
|
+
expect do
|
295
435
|
::Timeout.timeout(0.1) do
|
296
436
|
expect(::Test::Resource.to_json).to eq("Test::Resource")
|
297
437
|
end
|
298
|
-
|
438
|
+
end.not_to raise_error
|
299
439
|
end
|
300
440
|
end
|
301
441
|
|
302
|
-
describe "#
|
442
|
+
describe "#define_accessor" do
|
303
443
|
subject { ::Test::Resource.new }
|
304
444
|
|
305
|
-
it
|
445
|
+
it 'allows string fields to be set to nil' do
|
306
446
|
expect { subject.name = nil }.to_not raise_error
|
307
447
|
end
|
308
448
|
|
309
|
-
it
|
310
|
-
expect { subject.name = 1}.to raise_error(/name/)
|
449
|
+
it 'does not allow string fields to be set to Numeric' do
|
450
|
+
expect { subject.name = 1 }.to raise_error(/name/)
|
451
|
+
end
|
452
|
+
|
453
|
+
it 'does not allow a repeated field is set to nil' do
|
454
|
+
expect { subject.repeated_enum = nil }.to raise_error(TypeError)
|
455
|
+
end
|
456
|
+
|
457
|
+
context '#{simple_field_name}!' do
|
458
|
+
it 'returns value of set field' do
|
459
|
+
expect(::Test::Resource.new(:name => "Joe").name!).to eq("Joe")
|
460
|
+
end
|
461
|
+
|
462
|
+
it 'returns value of set field with default' do
|
463
|
+
expect(::Test::Resource.new(:name => "").name!).to eq("")
|
464
|
+
end
|
465
|
+
|
466
|
+
it 'returns nil if extension field is unset' do
|
467
|
+
expect(subject.ext_is_searchable!).to be_nil
|
468
|
+
end
|
469
|
+
|
470
|
+
it 'returns value of set extension field' do
|
471
|
+
message = ::Test::Resource.new(:ext_is_searchable => true)
|
472
|
+
expect(message.ext_is_searchable!).to be(true)
|
473
|
+
end
|
474
|
+
|
475
|
+
it 'returns value of set extension field with default' do
|
476
|
+
message = ::Test::Resource.new(:ext_is_searchable => false)
|
477
|
+
expect(message.ext_is_searchable!).to be(false)
|
478
|
+
end
|
479
|
+
|
480
|
+
it 'returns nil for an unset repeated field that has only be read' do
|
481
|
+
message = ::Test::Resource.new
|
482
|
+
expect(message.repeated_enum!).to be_nil
|
483
|
+
message.repeated_enum
|
484
|
+
expect(message.repeated_enum!).to be_nil
|
485
|
+
end
|
486
|
+
|
487
|
+
it 'returns value for an unset repeated field has been read and appended to' do
|
488
|
+
message = ::Test::Resource.new
|
489
|
+
message.repeated_enum << 1
|
490
|
+
expect(message.repeated_enum!).to eq([1])
|
491
|
+
end
|
492
|
+
|
493
|
+
it 'returns value for an unset repeated field has been explicitly set' do
|
494
|
+
message = ::Test::Resource.new
|
495
|
+
message.repeated_enum = [1]
|
496
|
+
expect(message.repeated_enum!).to eq([1])
|
497
|
+
end
|
311
498
|
end
|
312
499
|
end
|
313
500
|
|
@@ -317,12 +504,15 @@ describe Protobuf::Message do
|
|
317
504
|
expect(field).to be_a(::Protobuf::Field::BoolField)
|
318
505
|
expect(field.tag).to eq(100)
|
319
506
|
expect(field.name).to eq(:ext_is_searchable)
|
507
|
+
expect(field.fully_qualified_name).to eq(:'.test.Searchable.ext_is_searchable')
|
320
508
|
expect(field).to be_extension
|
321
509
|
end
|
322
510
|
|
323
511
|
it 'fetches an extension field by its symbolized name' do
|
324
512
|
expect(::Test::Resource.get_extension_field(:ext_is_searchable)).to be_a(::Protobuf::Field::BoolField)
|
325
513
|
expect(::Test::Resource.get_extension_field('ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
|
514
|
+
expect(::Test::Resource.get_extension_field(:'.test.Searchable.ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
|
515
|
+
expect(::Test::Resource.get_extension_field('.test.Searchable.ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
|
326
516
|
end
|
327
517
|
|
328
518
|
it 'returns nil when attempting to get a non-extension field' do
|
@@ -330,8 +520,91 @@ describe Protobuf::Message do
|
|
330
520
|
end
|
331
521
|
|
332
522
|
it 'returns nil when field is not found' do
|
333
|
-
::Test::Resource.get_extension_field(-1).
|
334
|
-
::Test::Resource.get_extension_field(nil).
|
523
|
+
expect(::Test::Resource.get_extension_field(-1)).to be_nil
|
524
|
+
expect(::Test::Resource.get_extension_field(nil)).to be_nil
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
describe '#field?' do
|
529
|
+
it 'returns false for non-existent field' do
|
530
|
+
expect(::Test::Resource.get_field('doesnotexist')).to be_nil
|
531
|
+
expect(::Test::Resource.new.field?('doesnotexist')).to be(false)
|
532
|
+
end
|
533
|
+
|
534
|
+
it 'returns false for unset field' do
|
535
|
+
expect(::Test::Resource.get_field('name')).to be
|
536
|
+
expect(::Test::Resource.new.field?('name')).to be(false)
|
537
|
+
end
|
538
|
+
|
539
|
+
it 'returns false for unset field from tag' do
|
540
|
+
expect(::Test::Resource.get_field(1)).to be
|
541
|
+
expect(::Test::Resource.new.field?(1)).to be(false)
|
542
|
+
end
|
543
|
+
|
544
|
+
it 'returns true for set field' do
|
545
|
+
expect(::Test::Resource.new(:name => "Joe").field?('name')).to be(true)
|
546
|
+
end
|
547
|
+
|
548
|
+
it 'returns true for set field with default' do
|
549
|
+
expect(::Test::Resource.new(:name => "").field?('name')).to be(true)
|
550
|
+
end
|
551
|
+
|
552
|
+
it 'returns true from field tag value' do
|
553
|
+
expect(::Test::Resource.new(:name => "Joe").field?(1)).to be(true)
|
554
|
+
end
|
555
|
+
|
556
|
+
it 'returns false for unset extension field' do
|
557
|
+
ext_field = :".test.Searchable.ext_is_searchable"
|
558
|
+
expect(::Test::Resource.get_extension_field(ext_field)).to be
|
559
|
+
expect(::Test::Resource.new.field?(ext_field)).to be(false)
|
560
|
+
end
|
561
|
+
|
562
|
+
it 'returns false for unset extension field from tag' do
|
563
|
+
expect(::Test::Resource.get_extension_field(100)).to be
|
564
|
+
expect(::Test::Resource.new.field?(100)).to be(false)
|
565
|
+
end
|
566
|
+
|
567
|
+
it 'returns true for set extension field' do
|
568
|
+
ext_field = :".test.Searchable.ext_is_searchable"
|
569
|
+
message = ::Test::Resource.new(ext_field => true)
|
570
|
+
expect(message.field?(ext_field)).to be(true)
|
571
|
+
end
|
572
|
+
|
573
|
+
it 'returns true for set extension field with default' do
|
574
|
+
ext_field = :".test.Searchable.ext_is_searchable"
|
575
|
+
message = ::Test::Resource.new(ext_field => false)
|
576
|
+
expect(message.field?(ext_field)).to be(true)
|
577
|
+
end
|
578
|
+
|
579
|
+
it 'returns true for set extension field from tag' do
|
580
|
+
ext_field = :".test.Searchable.ext_is_searchable"
|
581
|
+
message = ::Test::Resource.new(ext_field => false)
|
582
|
+
expect(message.field?(100)).to be(true)
|
583
|
+
end
|
584
|
+
|
585
|
+
it 'returns false for repeated field that has been read from' do
|
586
|
+
message = ::Test::Resource.new
|
587
|
+
expect(message.field?(:repeated_enum)).to be(false)
|
588
|
+
message.repeated_enum
|
589
|
+
expect(message.field?(:repeated_enum)).to be(false)
|
590
|
+
end
|
591
|
+
|
592
|
+
it 'returns true for a repeated field that has been read from and appended to' do
|
593
|
+
message = ::Test::Resource.new
|
594
|
+
message.repeated_enum << 1
|
595
|
+
expect(message.field?(:repeated_enum)).to be(true)
|
596
|
+
end
|
597
|
+
|
598
|
+
it 'returns true for a repeated field that has been set with the setter' do
|
599
|
+
message = ::Test::Resource.new
|
600
|
+
message.repeated_enum = [1]
|
601
|
+
expect(message.field?(:repeated_enum)).to be(true)
|
602
|
+
end
|
603
|
+
|
604
|
+
it 'returns false for a repeated field that has been replaced with []' do
|
605
|
+
message = ::Test::Resource.new
|
606
|
+
message.repeated_enum.replace([])
|
607
|
+
expect(message.field?(:repeated_enum)).to be(false)
|
335
608
|
end
|
336
609
|
end
|
337
610
|
|
@@ -341,6 +614,7 @@ describe Protobuf::Message do
|
|
341
614
|
expect(field).to be_a(::Protobuf::Field::StringField)
|
342
615
|
expect(field.tag).to eq(1)
|
343
616
|
expect(field.name).to eq(:name)
|
617
|
+
expect(field.fully_qualified_name).to eq(:name)
|
344
618
|
expect(field).not_to be_extension
|
345
619
|
end
|
346
620
|
|
@@ -351,8 +625,8 @@ describe Protobuf::Message do
|
|
351
625
|
|
352
626
|
it 'fetches an extension field when forced' do
|
353
627
|
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)
|
628
|
+
expect(::Test::Resource.get_field(:'.test.Searchable.ext_is_searchable', true)).to be_a(::Protobuf::Field::BoolField)
|
629
|
+
expect(::Test::Resource.get_field('.test.Searchable.ext_is_searchable', true)).to be_a(::Protobuf::Field::BoolField)
|
356
630
|
end
|
357
631
|
|
358
632
|
it 'returns nil when attempting to get an extension field' do
|
@@ -360,9 +634,234 @@ describe Protobuf::Message do
|
|
360
634
|
end
|
361
635
|
|
362
636
|
it 'returns nil when field is not defined' do
|
363
|
-
::Test::Resource.get_field(-1).
|
364
|
-
::Test::Resource.get_field(nil).
|
637
|
+
expect(::Test::Resource.get_field(-1)).to be_nil
|
638
|
+
expect(::Test::Resource.get_field(nil)).to be_nil
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
describe 'defining a field' do
|
643
|
+
# Case 1
|
644
|
+
context 'single base field' do
|
645
|
+
let(:klass) do
|
646
|
+
Class.new(Protobuf::Message) do
|
647
|
+
optional :string, :foo, 1
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
it 'has an accessor for foo' do
|
652
|
+
message = klass.new(:foo => 'bar')
|
653
|
+
expect(message.foo).to eq('bar')
|
654
|
+
expect(message[:foo]).to eq('bar')
|
655
|
+
expect(message['foo']).to eq('bar')
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
# Case 2
|
660
|
+
context 'base field and extension field name collision' do
|
661
|
+
let(:klass) do
|
662
|
+
Class.new(Protobuf::Message) do
|
663
|
+
optional :string, :foo, 1
|
664
|
+
optional :string, :".boom.foo", 2, :extension => true
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
it 'has an accessor for foo that refers to the base field' do
|
669
|
+
message = klass.new(:foo => 'bar', '.boom.foo' => 'bam')
|
670
|
+
expect(message.foo).to eq('bar')
|
671
|
+
expect(message[:foo]).to eq('bar')
|
672
|
+
expect(message['foo']).to eq('bar')
|
673
|
+
expect(message[:'.boom.foo']).to eq('bam')
|
674
|
+
expect(message['.boom.foo']).to eq('bam')
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
# Case 3
|
679
|
+
context 'no base field with extension fields with name collision' do
|
680
|
+
let(:klass) do
|
681
|
+
Class.new(Protobuf::Message) do
|
682
|
+
optional :string, :".boom.foo", 2, :extension => true
|
683
|
+
optional :string, :".goat.foo", 3, :extension => true
|
684
|
+
end
|
685
|
+
end
|
686
|
+
|
687
|
+
it 'has an accessor for foo that refers to the extension field' do
|
688
|
+
message = klass.new('.boom.foo' => 'bam', '.goat.foo' => 'red')
|
689
|
+
expect { message.foo }.to raise_error(NoMethodError)
|
690
|
+
expect { message[:foo] }.to raise_error(ArgumentError)
|
691
|
+
expect { message['foo'] }.to raise_error(ArgumentError)
|
692
|
+
expect(message[:'.boom.foo']).to eq('bam')
|
693
|
+
expect(message['.boom.foo']).to eq('bam')
|
694
|
+
expect(message[:'.goat.foo']).to eq('red')
|
695
|
+
expect(message['.goat.foo']).to eq('red')
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
# Case 4
|
700
|
+
context 'no base field with an extension field' do
|
701
|
+
let(:klass) do
|
702
|
+
Class.new(Protobuf::Message) do
|
703
|
+
optional :string, :".boom.foo", 2, :extension => true
|
704
|
+
end
|
705
|
+
end
|
706
|
+
|
707
|
+
it 'has an accessor for foo that refers to the extension field' do
|
708
|
+
message = klass.new('.boom.foo' => 'bam')
|
709
|
+
expect(message.foo).to eq('bam')
|
710
|
+
expect(message[:foo]).to eq('bam')
|
711
|
+
expect(message['foo']).to eq('bam')
|
712
|
+
expect(message[:'.boom.foo']).to eq('bam')
|
713
|
+
expect(message['.boom.foo']).to eq('bam')
|
714
|
+
end
|
365
715
|
end
|
366
716
|
end
|
367
717
|
|
718
|
+
describe '.[]=' do
|
719
|
+
context 'clearing fields' do
|
720
|
+
it 'clears repeated fields with an empty array' do
|
721
|
+
instance = ::Test::Resource.new(:repeated_enum => [::Test::StatusType::ENABLED])
|
722
|
+
expect(instance.field?(:repeated_enum)).to be(true)
|
723
|
+
instance[:repeated_enum] = []
|
724
|
+
expect(instance.field?(:repeated_enum)).to be(false)
|
725
|
+
end
|
726
|
+
|
727
|
+
it 'clears optional fields with nil' do
|
728
|
+
instance = ::Test::Resource.new(:name => "Joe")
|
729
|
+
expect(instance.field?(:name)).to be(true)
|
730
|
+
instance[:name] = nil
|
731
|
+
expect(instance.field?(:name)).to be(false)
|
732
|
+
end
|
733
|
+
|
734
|
+
it 'clears optional extenstion fields with nil' do
|
735
|
+
instance = ::Test::Resource.new(:ext_is_searchable => true)
|
736
|
+
expect(instance.field?(:ext_is_searchable)).to be(true)
|
737
|
+
instance[:ext_is_searchable] = nil
|
738
|
+
expect(instance.field?(:ext_is_searchable)).to be(false)
|
739
|
+
end
|
740
|
+
end
|
741
|
+
|
742
|
+
context 'setting fields' do
|
743
|
+
let(:instance) { ::Test::Resource.new }
|
744
|
+
|
745
|
+
it 'sets and replaces repeated fields' do
|
746
|
+
initial = [::Test::StatusType::ENABLED, ::Test::StatusType::DISABLED]
|
747
|
+
instance[:repeated_enum] = initial
|
748
|
+
expect(instance[:repeated_enum]).to eq(initial)
|
749
|
+
replacement = [::Test::StatusType::DELETED]
|
750
|
+
instance[:repeated_enum] = replacement
|
751
|
+
expect(instance[:repeated_enum]).to eq(replacement)
|
752
|
+
end
|
753
|
+
|
754
|
+
it 'sets acceptable optional field values' do
|
755
|
+
instance[:name] = "Joe"
|
756
|
+
expect(instance[:name]).to eq("Joe")
|
757
|
+
instance[1] = "Tom"
|
758
|
+
expect(instance[:name]).to eq("Tom")
|
759
|
+
end
|
760
|
+
|
761
|
+
it 'sets acceptable empty string field values' do
|
762
|
+
instance[:name] = ""
|
763
|
+
expect(instance.name!).to eq("")
|
764
|
+
end
|
765
|
+
|
766
|
+
it 'sets acceptable empty message field values' do
|
767
|
+
instance = ::Test::Nested.new
|
768
|
+
instance[:resource] = {}
|
769
|
+
expect(instance.resource!).to eq(::Test::Resource.new)
|
770
|
+
end
|
771
|
+
|
772
|
+
it 'sets acceptable extension field values' do
|
773
|
+
instance[:ext_is_searchable] = true
|
774
|
+
expect(instance[:ext_is_searchable]).to eq(true)
|
775
|
+
instance[:".test.Searchable.ext_is_searchable"] = false
|
776
|
+
expect(instance[:ext_is_searchable]).to eq(false)
|
777
|
+
instance[100] = true
|
778
|
+
expect(instance[:ext_is_searchable]).to eq(true)
|
779
|
+
end
|
780
|
+
|
781
|
+
# to be deprecated
|
782
|
+
it 'does nothing when sent an empty array' do
|
783
|
+
instance[:repeated_enum] = nil
|
784
|
+
expect(instance[:repeated_enum]).to eq([])
|
785
|
+
instance[:repeated_enum] = [1, 2]
|
786
|
+
expect(instance[:repeated_enum]).to eq([1, 2])
|
787
|
+
instance[:repeated_enum] = nil
|
788
|
+
# Yes this is very silly, but backwards compatible
|
789
|
+
expect(instance[:repeated_enum]).to eq([1, 2])
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
793
|
+
context 'throwing TypeError' do
|
794
|
+
let(:instance) { ::Test::Resource.new }
|
795
|
+
|
796
|
+
it 'throws when a repeated value is set with a non array' do
|
797
|
+
expect { instance[:repeated_enum] = "string" }.to raise_error(TypeError)
|
798
|
+
end
|
799
|
+
|
800
|
+
it 'throws when a repeated value is set with an array of the wrong type' do
|
801
|
+
expect { instance[:repeated_enum] = [true, false] }.to raise_error(TypeError)
|
802
|
+
end
|
803
|
+
|
804
|
+
it 'throws when an optional value is not #acceptable?' do
|
805
|
+
expect { instance[:name] = 1 }.to raise_error(TypeError)
|
806
|
+
end
|
807
|
+
end
|
808
|
+
|
809
|
+
context 'ignoring unknown fields' do
|
810
|
+
around do |example|
|
811
|
+
orig = ::Protobuf.ignore_unknown_fields?
|
812
|
+
::Protobuf.ignore_unknown_fields = true
|
813
|
+
example.call
|
814
|
+
::Protobuf.ignore_unknown_fields = orig
|
815
|
+
end
|
816
|
+
|
817
|
+
context 'with valid fields' do
|
818
|
+
let(:values) { { :name => "Jim" } }
|
819
|
+
|
820
|
+
it "does not raise an error" do
|
821
|
+
expect { ::Test::Resource.new(values) }.to_not raise_error
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
context 'with non-existent field' do
|
826
|
+
let(:values) { { :name => "Jim", :othername => "invalid" } }
|
827
|
+
|
828
|
+
it "does not raise an error" do
|
829
|
+
expect { ::Test::Resource.new(values) }.to_not raise_error
|
830
|
+
end
|
831
|
+
end
|
832
|
+
end
|
833
|
+
|
834
|
+
context 'not ignoring unknown fields' do
|
835
|
+
around do |example|
|
836
|
+
orig = ::Protobuf.ignore_unknown_fields?
|
837
|
+
::Protobuf.ignore_unknown_fields = false
|
838
|
+
example.call
|
839
|
+
::Protobuf.ignore_unknown_fields = orig
|
840
|
+
end
|
841
|
+
|
842
|
+
context 'with valid fields' do
|
843
|
+
let(:values) { { :name => "Jim" } }
|
844
|
+
|
845
|
+
it "does not raise an error" do
|
846
|
+
expect { ::Test::Resource.new(values) }.to_not raise_error
|
847
|
+
end
|
848
|
+
end
|
849
|
+
|
850
|
+
context 'with non-existent field' do
|
851
|
+
let(:values) { { :name => "Jim", :othername => "invalid" } }
|
852
|
+
|
853
|
+
it "raises an error and mentions the erroneous field" do
|
854
|
+
expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
|
855
|
+
end
|
856
|
+
|
857
|
+
context 'with a nil value' do
|
858
|
+
let(:values) { { :name => "Jim", :othername => nil } }
|
859
|
+
|
860
|
+
it "raises an error and mentions the erroneous field" do
|
861
|
+
expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
|
862
|
+
end
|
863
|
+
end
|
864
|
+
end
|
865
|
+
end
|
866
|
+
end
|
368
867
|
end
|