protobuf-cucumber 3.10.4
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 +7 -0
- data/.gitignore +21 -0
- data/.rubocop.yml +70 -0
- data/.rubocop_todo.yml +145 -0
- data/.travis.yml +40 -0
- data/.yardopts +5 -0
- data/CHANGES.md +344 -0
- data/CONTRIBUTING.md +16 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +64 -0
- data/bin/protoc-gen-ruby +22 -0
- data/bin/rpc_server +5 -0
- data/install-protobuf.sh +28 -0
- data/lib/protobuf.rb +129 -0
- data/lib/protobuf/cli.rb +257 -0
- data/lib/protobuf/code_generator.rb +120 -0
- data/lib/protobuf/decoder.rb +28 -0
- data/lib/protobuf/deprecation.rb +117 -0
- data/lib/protobuf/descriptors.rb +3 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +62 -0
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +301 -0
- data/lib/protobuf/encoder.rb +11 -0
- data/lib/protobuf/enum.rb +365 -0
- data/lib/protobuf/exceptions.rb +9 -0
- data/lib/protobuf/field.rb +74 -0
- data/lib/protobuf/field/base_field.rb +380 -0
- data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
- data/lib/protobuf/field/bool_field.rb +64 -0
- data/lib/protobuf/field/bytes_field.rb +78 -0
- data/lib/protobuf/field/double_field.rb +25 -0
- data/lib/protobuf/field/enum_field.rb +61 -0
- data/lib/protobuf/field/field_array.rb +104 -0
- data/lib/protobuf/field/field_hash.rb +122 -0
- data/lib/protobuf/field/fixed32_field.rb +25 -0
- data/lib/protobuf/field/fixed64_field.rb +28 -0
- data/lib/protobuf/field/float_field.rb +43 -0
- data/lib/protobuf/field/int32_field.rb +21 -0
- data/lib/protobuf/field/int64_field.rb +34 -0
- data/lib/protobuf/field/integer_field.rb +23 -0
- data/lib/protobuf/field/message_field.rb +51 -0
- data/lib/protobuf/field/sfixed32_field.rb +27 -0
- data/lib/protobuf/field/sfixed64_field.rb +28 -0
- data/lib/protobuf/field/signed_integer_field.rb +29 -0
- data/lib/protobuf/field/sint32_field.rb +21 -0
- data/lib/protobuf/field/sint64_field.rb +21 -0
- data/lib/protobuf/field/string_field.rb +51 -0
- data/lib/protobuf/field/uint32_field.rb +21 -0
- data/lib/protobuf/field/uint64_field.rb +21 -0
- data/lib/protobuf/field/varint_field.rb +77 -0
- data/lib/protobuf/generators/base.rb +85 -0
- data/lib/protobuf/generators/enum_generator.rb +39 -0
- data/lib/protobuf/generators/extension_generator.rb +27 -0
- data/lib/protobuf/generators/field_generator.rb +193 -0
- data/lib/protobuf/generators/file_generator.rb +262 -0
- data/lib/protobuf/generators/group_generator.rb +122 -0
- data/lib/protobuf/generators/message_generator.rb +104 -0
- data/lib/protobuf/generators/option_generator.rb +17 -0
- data/lib/protobuf/generators/printable.rb +160 -0
- data/lib/protobuf/generators/service_generator.rb +50 -0
- data/lib/protobuf/lifecycle.rb +33 -0
- data/lib/protobuf/logging.rb +39 -0
- data/lib/protobuf/message.rb +260 -0
- data/lib/protobuf/message/fields.rb +233 -0
- data/lib/protobuf/message/serialization.rb +85 -0
- data/lib/protobuf/optionable.rb +70 -0
- data/lib/protobuf/rpc/buffer.rb +78 -0
- data/lib/protobuf/rpc/client.rb +140 -0
- data/lib/protobuf/rpc/connectors/base.rb +221 -0
- data/lib/protobuf/rpc/connectors/ping.rb +89 -0
- data/lib/protobuf/rpc/connectors/socket.rb +78 -0
- data/lib/protobuf/rpc/connectors/zmq.rb +319 -0
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +50 -0
- data/lib/protobuf/rpc/env.rb +60 -0
- data/lib/protobuf/rpc/error.rb +28 -0
- data/lib/protobuf/rpc/error/client_error.rb +31 -0
- data/lib/protobuf/rpc/error/server_error.rb +43 -0
- data/lib/protobuf/rpc/middleware.rb +25 -0
- data/lib/protobuf/rpc/middleware/exception_handler.rb +40 -0
- data/lib/protobuf/rpc/middleware/logger.rb +95 -0
- data/lib/protobuf/rpc/middleware/request_decoder.rb +79 -0
- data/lib/protobuf/rpc/middleware/response_encoder.rb +83 -0
- data/lib/protobuf/rpc/middleware/runner.rb +18 -0
- data/lib/protobuf/rpc/rpc.pb.rb +64 -0
- data/lib/protobuf/rpc/rpc_method.rb +16 -0
- data/lib/protobuf/rpc/server.rb +39 -0
- data/lib/protobuf/rpc/servers/socket/server.rb +121 -0
- data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
- data/lib/protobuf/rpc/servers/socket_runner.rb +46 -0
- data/lib/protobuf/rpc/servers/zmq/broker.rb +194 -0
- data/lib/protobuf/rpc/servers/zmq/server.rb +321 -0
- data/lib/protobuf/rpc/servers/zmq/util.rb +48 -0
- data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
- data/lib/protobuf/rpc/servers/zmq_runner.rb +70 -0
- data/lib/protobuf/rpc/service.rb +172 -0
- data/lib/protobuf/rpc/service_directory.rb +261 -0
- data/lib/protobuf/rpc/service_dispatcher.rb +45 -0
- data/lib/protobuf/rpc/service_filters.rb +250 -0
- data/lib/protobuf/rpc/stat.rb +119 -0
- data/lib/protobuf/socket.rb +21 -0
- data/lib/protobuf/tasks.rb +1 -0
- data/lib/protobuf/tasks/compile.rake +80 -0
- data/lib/protobuf/varint.rb +20 -0
- data/lib/protobuf/varint_pure.rb +31 -0
- data/lib/protobuf/version.rb +3 -0
- data/lib/protobuf/wire_type.rb +10 -0
- data/lib/protobuf/zmq.rb +21 -0
- data/profile.html +5103 -0
- data/proto/dynamic_discovery.proto +44 -0
- data/proto/google/protobuf/compiler/plugin.proto +147 -0
- data/proto/google/protobuf/descriptor.proto +779 -0
- data/proto/rpc.proto +69 -0
- data/protobuf-cucumber.gemspec +57 -0
- data/spec/benchmark/tasks.rb +143 -0
- data/spec/bin/protoc-gen-ruby_spec.rb +23 -0
- data/spec/encoding/all_types_spec.rb +103 -0
- 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 +58 -0
- data/spec/functional/socket_server_spec.rb +59 -0
- data/spec/functional/zmq_server_spec.rb +105 -0
- data/spec/lib/protobuf/cli_spec.rb +317 -0
- data/spec/lib/protobuf/code_generator_spec.rb +87 -0
- data/spec/lib/protobuf/enum_spec.rb +307 -0
- 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 +44 -0
- data/spec/lib/protobuf/field/field_array_spec.rb +105 -0
- data/spec/lib/protobuf/field/field_hash_spec.rb +168 -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 +120 -0
- 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 +79 -0
- 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 +192 -0
- data/spec/lib/protobuf/generators/base_spec.rb +154 -0
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +82 -0
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +42 -0
- data/spec/lib/protobuf/generators/field_generator_spec.rb +197 -0
- data/spec/lib/protobuf/generators/file_generator_spec.rb +119 -0
- data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
- data/spec/lib/protobuf/generators/service_generator_spec.rb +99 -0
- data/spec/lib/protobuf/lifecycle_spec.rb +94 -0
- data/spec/lib/protobuf/message_spec.rb +944 -0
- data/spec/lib/protobuf/optionable_spec.rb +265 -0
- data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +226 -0
- data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +34 -0
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +110 -0
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +91 -0
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +43 -0
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +293 -0
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +517 -0
- data/spec/lib/protobuf/rpc/service_spec.rb +162 -0
- data/spec/lib/protobuf/rpc/stat_spec.rb +101 -0
- data/spec/lib/protobuf/varint_spec.rb +29 -0
- data/spec/lib/protobuf_spec.rb +105 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/support/all.rb +6 -0
- data/spec/support/packed_field.rb +23 -0
- data/spec/support/protos/all_types.data.bin +0 -0
- data/spec/support/protos/all_types.data.txt +119 -0
- data/spec/support/protos/enum.pb.rb +63 -0
- data/spec/support/protos/enum.proto +37 -0
- data/spec/support/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/protos/google_unittest.proto +884 -0
- data/spec/support/protos/google_unittest_custom_options.bin +0 -0
- data/spec/support/protos/google_unittest_custom_options.pb.rb +361 -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/protos/google_unittest_import.proto +73 -0
- data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
- data/spec/support/protos/google_unittest_import_public.proto +41 -0
- data/spec/support/protos/map-test.bin +157 -0
- data/spec/support/protos/map-test.pb.rb +85 -0
- data/spec/support/protos/map-test.proto +68 -0
- data/spec/support/protos/multi_field_extensions.pb.rb +59 -0
- data/spec/support/protos/multi_field_extensions.proto +35 -0
- data/spec/support/protos/resource.pb.rb +172 -0
- data/spec/support/protos/resource.proto +137 -0
- data/spec/support/resource_service.rb +23 -0
- data/spec/support/server.rb +65 -0
- data/spec/support/test_app_file.rb +2 -0
- data/varint_prof.rb +82 -0
- metadata +579 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'protobuf/generators/file_generator'
|
4
|
+
|
5
|
+
RSpec.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
|
+
specify { expect(subject.file_name).to eq('test/foo.pb.rb') }
|
13
|
+
|
14
|
+
describe '#print_import_requires' do
|
15
|
+
let(:descriptor_fields) do
|
16
|
+
base_descriptor_fields.merge(
|
17
|
+
:dependency => [
|
18
|
+
'test/bar.proto',
|
19
|
+
'test/baz.proto',
|
20
|
+
],
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'prints a ruby require for each dependency' do
|
25
|
+
expect(subject).to receive(:print_require).with('test/bar.pb', false)
|
26
|
+
expect(subject).to receive(:print_require).with('test/baz.pb', false)
|
27
|
+
subject.print_import_requires
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'prints a ruby require_relative for each dependency if environment variable was set' do
|
31
|
+
expect(subject).to receive(:print_require).with('test/bar.pb', true)
|
32
|
+
expect(subject).to receive(:print_require).with('test/baz.pb', true)
|
33
|
+
ENV['PB_REQUIRE_RELATIVE'] = 'true'
|
34
|
+
subject.print_import_requires
|
35
|
+
ENV.delete('PB_REQUIRE_RELATIVE')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#compile' do
|
40
|
+
it 'generates the file contents' do
|
41
|
+
subject.compile
|
42
|
+
expect(subject.to_s).to eq <<EOF
|
43
|
+
# encoding: utf-8
|
44
|
+
|
45
|
+
##
|
46
|
+
# This file is auto-generated. DO NOT EDIT!
|
47
|
+
#
|
48
|
+
require 'protobuf'
|
49
|
+
|
50
|
+
EOF
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'generates the file contents using default package name' do
|
54
|
+
allow(ENV).to receive(:key?).with('PB_ALLOW_DEFAULT_PACKAGE_NAME')
|
55
|
+
.and_return(true)
|
56
|
+
subject.compile
|
57
|
+
expect(subject.to_s).to eq <<EOF
|
58
|
+
# encoding: utf-8
|
59
|
+
|
60
|
+
##
|
61
|
+
# This file is auto-generated. DO NOT EDIT!
|
62
|
+
#
|
63
|
+
require 'protobuf'
|
64
|
+
|
65
|
+
module Foo
|
66
|
+
::Protobuf::Optionable.inject(self) { ::Google::Protobuf::FileOptions }
|
67
|
+
end
|
68
|
+
|
69
|
+
EOF
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'with extended messages' do
|
73
|
+
let(:descriptor_fields) do
|
74
|
+
base_descriptor_fields.merge(
|
75
|
+
:package => 'test.pkg.file_generator_spec',
|
76
|
+
:extension => [{
|
77
|
+
:name => 'boom',
|
78
|
+
:number => 20_000,
|
79
|
+
:label => Google::Protobuf::FieldDescriptorProto::Label::LABEL_OPTIONAL,
|
80
|
+
:type => Google::Protobuf::FieldDescriptorProto::Type::TYPE_STRING,
|
81
|
+
:extendee => '.google.protobuf.FieldOptions',
|
82
|
+
}],
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'generates the file contents that include the namespaced extension name' do
|
87
|
+
subject.compile
|
88
|
+
expect(subject.to_s).to eq <<EOF
|
89
|
+
# encoding: utf-8
|
90
|
+
|
91
|
+
##
|
92
|
+
# This file is auto-generated. DO NOT EDIT!
|
93
|
+
#
|
94
|
+
require 'protobuf'
|
95
|
+
|
96
|
+
module Test
|
97
|
+
module Pkg
|
98
|
+
module File_generator_spec
|
99
|
+
::Protobuf::Optionable.inject(self) { ::Google::Protobuf::FileOptions }
|
100
|
+
|
101
|
+
##
|
102
|
+
# Extended Message Fields
|
103
|
+
#
|
104
|
+
class ::Google::Protobuf::FieldOptions < ::Protobuf::Message
|
105
|
+
optional :string, :".test.pkg.file_generator_spec.boom", 20000, :extension => true
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
EOF
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
File without changes
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'protobuf/generators/service_generator'
|
4
|
+
|
5
|
+
RSpec.describe ::Protobuf::Generators::ServiceGenerator do
|
6
|
+
|
7
|
+
class ::CustomMethodEnum < ::Protobuf::Enum
|
8
|
+
define :BOOM, 1
|
9
|
+
define :BAM, 2
|
10
|
+
end
|
11
|
+
|
12
|
+
class ::CustomMethodMessage < ::Protobuf::Message
|
13
|
+
optional :string, :foo, 1
|
14
|
+
end
|
15
|
+
|
16
|
+
class ::Google::Protobuf::MethodOptions < ::Protobuf::Message
|
17
|
+
optional :string, :custom_string_option, 22000, :extension => true
|
18
|
+
optional :bool, :custom_bool_option, 22001, :extension => true
|
19
|
+
optional :int32, :custom_int32_option, 22002, :extension => true
|
20
|
+
optional ::CustomMethodEnum, :custom_enum_option, 22003, :extension => true
|
21
|
+
optional ::CustomMethodMessage, :custom_message_option, 22004, :extension => true
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:methods) do
|
25
|
+
[
|
26
|
+
{ :name => 'Search', :input_type => 'FooRequest', :output_type => 'FooResponse' },
|
27
|
+
{
|
28
|
+
:name => 'FooBar',
|
29
|
+
:input_type => '.foo.Request',
|
30
|
+
:output_type => '.bar.Response',
|
31
|
+
:options => {
|
32
|
+
:custom_string_option => 'boom',
|
33
|
+
:custom_bool_option => true,
|
34
|
+
:custom_int32_option => 123,
|
35
|
+
:custom_message_option => CustomMethodMessage.new(:foo => 'bam'),
|
36
|
+
:custom_enum_option => CustomMethodEnum::BAM,
|
37
|
+
},
|
38
|
+
},
|
39
|
+
]
|
40
|
+
end
|
41
|
+
let(:service_fields) do
|
42
|
+
{
|
43
|
+
:name => 'TestService',
|
44
|
+
:method => methods,
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:service) { ::Google::Protobuf::ServiceDescriptorProto.new(service_fields) }
|
49
|
+
|
50
|
+
subject(:service_generator) { described_class.new(service) }
|
51
|
+
|
52
|
+
describe '#compile' do
|
53
|
+
let(:compiled) do
|
54
|
+
<<EOF
|
55
|
+
class TestService < ::Protobuf::Rpc::Service
|
56
|
+
rpc :search, FooRequest, FooResponse
|
57
|
+
rpc :foo_bar, ::Foo::Request, ::Bar::Response do
|
58
|
+
set_option :custom_string_option, "boom"
|
59
|
+
set_option :custom_bool_option, true
|
60
|
+
set_option :custom_int32_option, 123
|
61
|
+
set_option :custom_enum_option, ::CustomMethodEnum::BAM
|
62
|
+
set_option :custom_message_option, { :foo => "bam" }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
EOF
|
67
|
+
end
|
68
|
+
|
69
|
+
it "compiles the service and it's rpc methods" do
|
70
|
+
subject.compile
|
71
|
+
expect(subject.to_s).to eq(compiled)
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with PB_USE_RAW_RPC_NAMES in the environemnt' do
|
75
|
+
let(:compiled) do
|
76
|
+
<<EOF
|
77
|
+
class TestService < ::Protobuf::Rpc::Service
|
78
|
+
rpc :Search, FooRequest, FooResponse
|
79
|
+
rpc :FooBar, ::Foo::Request, ::Bar::Response do
|
80
|
+
set_option :custom_string_option, "boom"
|
81
|
+
set_option :custom_bool_option, true
|
82
|
+
set_option :custom_int32_option, 123
|
83
|
+
set_option :custom_enum_option, ::CustomMethodEnum::BAM
|
84
|
+
set_option :custom_message_option, { :foo => "bam" }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
EOF
|
89
|
+
end
|
90
|
+
|
91
|
+
before { allow(ENV).to receive(:key?).with('PB_USE_RAW_RPC_NAMES').and_return(true) }
|
92
|
+
|
93
|
+
it 'uses the raw RPC name and does not underscore it' do
|
94
|
+
subject.compile
|
95
|
+
expect(subject.to_s).to eq(compiled)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'protobuf/lifecycle'
|
3
|
+
|
4
|
+
RSpec.describe ::Protobuf::Lifecycle do
|
5
|
+
subject { described_class }
|
6
|
+
|
7
|
+
around do |example|
|
8
|
+
# this entire class is deprecated
|
9
|
+
::Protobuf.deprecator.silence(&example)
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
13
|
+
::ActiveSupport::Notifications.notifier = ::ActiveSupport::Notifications::Fanout.new
|
14
|
+
end
|
15
|
+
|
16
|
+
it "registers a string as the event_name" do
|
17
|
+
expect(::ActiveSupport::Notifications).to receive(:subscribe).with("something")
|
18
|
+
subject.register("something") { true }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "only registers blocks for event callbacks" do
|
22
|
+
expect do
|
23
|
+
subject.register("something")
|
24
|
+
end.to raise_error(/block/)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "calls the registered block when triggered" do
|
28
|
+
this = nil
|
29
|
+
subject.register("this") do
|
30
|
+
this = "not nil"
|
31
|
+
end
|
32
|
+
|
33
|
+
subject.trigger("this")
|
34
|
+
expect(this).to_not be_nil
|
35
|
+
expect(this).to eq("not nil")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "calls multiple registered blocks when triggered" do
|
39
|
+
this = nil
|
40
|
+
that = nil
|
41
|
+
|
42
|
+
subject.register("this") do
|
43
|
+
this = "not nil"
|
44
|
+
end
|
45
|
+
|
46
|
+
subject.register("this") do
|
47
|
+
that = "not nil"
|
48
|
+
end
|
49
|
+
|
50
|
+
subject.trigger("this")
|
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")
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when the registered block has arity' do
|
58
|
+
context 'and the triggered event does not have args' do
|
59
|
+
it 'does not pass the args' do
|
60
|
+
outer_bar = nil
|
61
|
+
|
62
|
+
subject.register('foo') do |bar|
|
63
|
+
expect(bar).to be_nil
|
64
|
+
outer_bar = 'triggered'
|
65
|
+
end
|
66
|
+
|
67
|
+
subject.trigger('foo')
|
68
|
+
expect(outer_bar).to eq 'triggered'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'and the triggered event has arguments' do
|
73
|
+
it 'does not pass the args' do
|
74
|
+
outer_bar = nil
|
75
|
+
|
76
|
+
subject.register('foo') do |bar|
|
77
|
+
expect(bar).to_not be_nil
|
78
|
+
outer_bar = bar
|
79
|
+
end
|
80
|
+
|
81
|
+
subject.trigger('foo', 'baz')
|
82
|
+
expect(outer_bar).to eq 'baz'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "normalized event names" do
|
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") }
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,944 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
require 'spec_helper'
|
5
|
+
require PROTOS_PATH.join('resource.pb')
|
6
|
+
require PROTOS_PATH.join('enum.pb')
|
7
|
+
|
8
|
+
RSpec.describe Protobuf::Message do
|
9
|
+
|
10
|
+
describe '.decode' do
|
11
|
+
let(:message) { ::Test::Resource.new(:name => "Jim") }
|
12
|
+
|
13
|
+
it 'creates a new message object decoded from the given bytes' do
|
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
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe 'defining a new field' do
|
87
|
+
context 'when defining a field with a tag that has already been used' do
|
88
|
+
it 'raises a TagCollisionError' do
|
89
|
+
expect do
|
90
|
+
Class.new(Protobuf::Message) do
|
91
|
+
optional ::Protobuf::Field::Int32Field, :foo, 1
|
92
|
+
optional ::Protobuf::Field::Int32Field, :bar, 1
|
93
|
+
end
|
94
|
+
end.to raise_error(Protobuf::TagCollisionError, /Field number 1 has already been used/)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'when defining an extension field with a tag that has already been used' do
|
99
|
+
it 'raises a TagCollisionError' do
|
100
|
+
expect do
|
101
|
+
Class.new(Protobuf::Message) do
|
102
|
+
extensions 100...110
|
103
|
+
optional ::Protobuf::Field::Int32Field, :foo, 100
|
104
|
+
optional ::Protobuf::Field::Int32Field, :bar, 100, :extension => true
|
105
|
+
end
|
106
|
+
end.to raise_error(Protobuf::TagCollisionError, /Field number 100 has already been used/)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'when defining a field with a name that has already been used' do
|
111
|
+
it 'raises a DuplicateFieldNameError' do
|
112
|
+
expect do
|
113
|
+
Class.new(Protobuf::Message) do
|
114
|
+
optional ::Protobuf::Field::Int32Field, :foo, 1
|
115
|
+
optional ::Protobuf::Field::Int32Field, :foo, 2
|
116
|
+
end
|
117
|
+
end.to raise_error(Protobuf::DuplicateFieldNameError, /Field name foo has already been used/)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when defining an extension field with a name that has already been used' do
|
122
|
+
it 'raises a DuplicateFieldNameError' do
|
123
|
+
expect do
|
124
|
+
Class.new(Protobuf::Message) do
|
125
|
+
extensions 100...110
|
126
|
+
optional ::Protobuf::Field::Int32Field, :foo, 1
|
127
|
+
optional ::Protobuf::Field::Int32Field, :foo, 100, :extension => true
|
128
|
+
end
|
129
|
+
end.to raise_error(Protobuf::DuplicateFieldNameError, /Field name foo has already been used/)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '.encode' do
|
135
|
+
let(:values) { { :name => "Jim" } }
|
136
|
+
|
137
|
+
it 'creates a new message object with the given values and returns the encoded bytes' do
|
138
|
+
expect(::Test::Resource.encode(values)).to eq ::Test::Resource.new(values).encode
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe '#initialize' do
|
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
|
149
|
+
test_enum = Test::EnumTestMessage.new
|
150
|
+
expect(test_enum.non_default_enum.name).to eq(Test::EnumTestType.enums.first.name)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "exposes the enum getter raw value through ! method" do
|
154
|
+
test_enum = Test::EnumTestMessage.new
|
155
|
+
expect(test_enum.non_default_enum!).to be_nil
|
156
|
+
end
|
157
|
+
|
158
|
+
it "exposes the enum getter raw value through ! method (when set)" do
|
159
|
+
test_enum = Test::EnumTestMessage.new
|
160
|
+
test_enum.non_default_enum = 1
|
161
|
+
expect(test_enum.non_default_enum!).to eq(1)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "does not try to set attributes which have nil values" do
|
165
|
+
expect_any_instance_of(Test::EnumTestMessage).not_to receive("non_default_enum=")
|
166
|
+
Test::EnumTestMessage.new(:non_default_enum => nil)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "takes a hash as an initialization argument" do
|
170
|
+
test_enum = Test::EnumTestMessage.new(:non_default_enum => 2)
|
171
|
+
expect(test_enum.non_default_enum).to eq(2)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "initializes with an object that responds to #to_hash" do
|
175
|
+
hashie_object = OpenStruct.new(:to_hash => { :non_default_enum => 2 })
|
176
|
+
test_enum = Test::EnumTestMessage.new(hashie_object)
|
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([])
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe '#encode' do
|
193
|
+
context "encoding" do
|
194
|
+
it "accepts UTF-8 strings into string fields" do
|
195
|
+
message = ::Test::Resource.new(:name => "Kyle Redfearn\u0060s iPad")
|
196
|
+
|
197
|
+
expect { message.encode }.to_not raise_error
|
198
|
+
end
|
199
|
+
|
200
|
+
it "keeps utf-8 when utf-8 is input for string fields" do
|
201
|
+
name = 'my name💩'
|
202
|
+
name.force_encoding(Encoding::UTF_8)
|
203
|
+
|
204
|
+
message = ::Test::Resource.new(:name => name)
|
205
|
+
new_message = ::Test::Resource.decode(message.encode)
|
206
|
+
expect(new_message.name == name).to be true
|
207
|
+
end
|
208
|
+
|
209
|
+
it "trims binary when binary is input for string fields" do
|
210
|
+
name = "my name\xC3"
|
211
|
+
name.force_encoding(Encoding::BINARY)
|
212
|
+
|
213
|
+
message = ::Test::Resource.new(:name => name)
|
214
|
+
new_message = ::Test::Resource.decode(message.encode)
|
215
|
+
expect(new_message.name == "my name").to be true
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
context "when there's no value for a required field" do
|
220
|
+
let(:message) { ::Test::ResourceWithRequiredField.new }
|
221
|
+
|
222
|
+
it "raises a 'message not initialized' error" do
|
223
|
+
expect do
|
224
|
+
message.encode
|
225
|
+
end.to raise_error(Protobuf::SerializationError, /required/i)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context "repeated fields" do
|
230
|
+
let(:message) { ::Test::Resource.new(:name => "something") }
|
231
|
+
|
232
|
+
it "does not raise an error when repeated fields are []" do
|
233
|
+
expect do
|
234
|
+
message.repeated_enum = []
|
235
|
+
message.encode
|
236
|
+
end.to_not raise_error
|
237
|
+
end
|
238
|
+
|
239
|
+
it "sets the value to nil when empty array is passed" do
|
240
|
+
message.repeated_enum = []
|
241
|
+
expect(message.instance_variable_get("@values")[:repeated_enum]).to be_nil
|
242
|
+
end
|
243
|
+
|
244
|
+
it "does not compact the edit original array" do
|
245
|
+
a = [nil].freeze
|
246
|
+
message.repeated_enum = a
|
247
|
+
expect(message.repeated_enum).to eq([])
|
248
|
+
expect(a).to eq([nil].freeze)
|
249
|
+
end
|
250
|
+
|
251
|
+
it "compacts the set array" do
|
252
|
+
message.repeated_enum = [nil]
|
253
|
+
expect(message.repeated_enum).to eq([])
|
254
|
+
end
|
255
|
+
|
256
|
+
it "raises TypeError when a non-array replaces it" do
|
257
|
+
expect do
|
258
|
+
message.repeated_enum = 2
|
259
|
+
end.to raise_error(/value of type/)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "boolean predicate methods" do
|
265
|
+
subject { Test::ResourceFindRequest.new(:name => "resource") }
|
266
|
+
|
267
|
+
it { is_expected.to respond_to(:active?) }
|
268
|
+
|
269
|
+
it "sets the predicate to true when the boolean value is true" do
|
270
|
+
subject.active = true
|
271
|
+
expect(subject.active?).to be true
|
272
|
+
end
|
273
|
+
|
274
|
+
it "sets the predicate to false when the boolean value is false" do
|
275
|
+
subject.active = false
|
276
|
+
expect(subject.active?).to be false
|
277
|
+
end
|
278
|
+
|
279
|
+
it "does not put predicate methods on non-boolean fields" do
|
280
|
+
expect(Test::ResourceFindRequest.new(:name => "resource")).to_not respond_to(:name?)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe "#respond_to_and_has?" do
|
285
|
+
subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
|
286
|
+
|
287
|
+
it "is false when the message does not have the field" do
|
288
|
+
expect(subject.respond_to_and_has?(:other_field)).to be false
|
289
|
+
end
|
290
|
+
|
291
|
+
it "is true when the message has the field" do
|
292
|
+
expect(subject.respond_to_and_has?(:non_default_enum)).to be true
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe "#respond_to_has_and_present?" do
|
297
|
+
subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
|
298
|
+
|
299
|
+
it "is false when the message does not have the field" do
|
300
|
+
expect(subject.respond_to_and_has_and_present?(:other_field)).to be false
|
301
|
+
end
|
302
|
+
|
303
|
+
it "is false when the field is repeated and a value is not present" do
|
304
|
+
expect(subject.respond_to_and_has_and_present?(:repeated_enums)).to be false
|
305
|
+
end
|
306
|
+
|
307
|
+
it "is false when the field is repeated and the value is empty array" do
|
308
|
+
subject.repeated_enums = []
|
309
|
+
expect(subject.respond_to_and_has_and_present?(:repeated_enums)).to be false
|
310
|
+
end
|
311
|
+
|
312
|
+
it "is true when the field is repeated and a value is present" do
|
313
|
+
subject.repeated_enums = [2]
|
314
|
+
expect(subject.respond_to_and_has_and_present?(:repeated_enums)).to be true
|
315
|
+
end
|
316
|
+
|
317
|
+
it "is true when the message has the field" do
|
318
|
+
expect(subject.respond_to_and_has_and_present?(:non_default_enum)).to be true
|
319
|
+
end
|
320
|
+
|
321
|
+
context "#API" do
|
322
|
+
subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
|
323
|
+
|
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?) }
|
332
|
+
end
|
333
|
+
|
334
|
+
end
|
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
|
+
|
359
|
+
describe '#to_hash' do
|
360
|
+
context 'generating values for an ENUM field' do
|
361
|
+
it 'converts the enum to its tag representation' do
|
362
|
+
hash = Test::EnumTestMessage.new(:non_default_enum => :TWO).to_hash
|
363
|
+
expect(hash).to eq(:non_default_enum => 2)
|
364
|
+
end
|
365
|
+
|
366
|
+
it 'does not populate default values' do
|
367
|
+
hash = Test::EnumTestMessage.new.to_hash
|
368
|
+
expect(hash).to eq({})
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'converts repeated enum fields to an array of the tags' do
|
372
|
+
hash = Test::EnumTestMessage.new(:repeated_enums => [:ONE, :TWO, :TWO, :ONE]).to_hash
|
373
|
+
expect(hash).to eq(:repeated_enums => [1, 2, 2, 1])
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
context 'generating values for a Message field' do
|
378
|
+
it 'recursively hashes field messages' do
|
379
|
+
hash = Test::Nested.new(:resource => { :name => 'Nested' }).to_hash
|
380
|
+
expect(hash).to eq(:resource => { :name => 'Nested' })
|
381
|
+
end
|
382
|
+
|
383
|
+
it 'recursively hashes a repeated set of messages' do
|
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
|
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
|
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)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe '#to_json' do
|
425
|
+
subject do
|
426
|
+
::Test::ResourceFindRequest.new(:name => 'Test Name', :active => false)
|
427
|
+
end
|
428
|
+
|
429
|
+
specify { expect(subject.to_json).to eq '{"name":"Test Name","active":false}' }
|
430
|
+
|
431
|
+
context 'for byte fields' do
|
432
|
+
let(:bytes) { "\x06\x8D1HP\x17:b".force_encoding(Encoding::ASCII_8BIT) }
|
433
|
+
|
434
|
+
subject do
|
435
|
+
::Test::ResourceFindRequest.new(:widget_bytes => [bytes])
|
436
|
+
end
|
437
|
+
|
438
|
+
specify { expect(subject.to_json).to eq '{"widget_bytes":["Bo0xSFAXOmI="]}' }
|
439
|
+
end
|
440
|
+
|
441
|
+
context 'using lower camel case field names' do
|
442
|
+
let(:bytes) { "\x06\x8D1HP\x17:b".force_encoding(Encoding::ASCII_8BIT) }
|
443
|
+
|
444
|
+
subject do
|
445
|
+
::Test::ResourceFindRequest.new(:widget_bytes => [bytes])
|
446
|
+
end
|
447
|
+
|
448
|
+
specify { expect(subject.to_json(:lower_camel_case => true)).to eq '{"widgetBytes":["Bo0xSFAXOmI="]}' }
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
describe '.from_json' do
|
453
|
+
it 'decodes optional bytes field with base64' do
|
454
|
+
expected_single_bytes = "\x06\x8D1HP\x17:b".unpack('C*')
|
455
|
+
single_bytes = ::Test::ResourceFindRequest
|
456
|
+
.from_json('{"singleBytes":"Bo0xSFAXOmI="}')
|
457
|
+
.single_bytes.unpack('C*')
|
458
|
+
|
459
|
+
expect(single_bytes).to(eq(expected_single_bytes))
|
460
|
+
end
|
461
|
+
|
462
|
+
it 'decodes repeated bytes field with base64' do
|
463
|
+
expected_widget_bytes = ["\x06\x8D1HP\x17:b"].map { |s| s.unpack('C*') }
|
464
|
+
widget_bytes = ::Test::ResourceFindRequest
|
465
|
+
.from_json('{"widgetBytes":["Bo0xSFAXOmI="]}')
|
466
|
+
.widget_bytes.map { |s| s.unpack('C*') }
|
467
|
+
|
468
|
+
expect(widget_bytes).to(eq(expected_widget_bytes))
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
describe '.to_json' do
|
473
|
+
it 'returns the class name of the message for use in json encoding' do
|
474
|
+
expect do
|
475
|
+
::Timeout.timeout(0.1) do
|
476
|
+
expect(::Test::Resource.to_json).to eq("Test::Resource")
|
477
|
+
end
|
478
|
+
end.not_to raise_error
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
describe "#define_accessor" do
|
483
|
+
subject { ::Test::Resource.new }
|
484
|
+
|
485
|
+
it 'allows string fields to be set to nil' do
|
486
|
+
expect { subject.name = nil }.to_not raise_error
|
487
|
+
end
|
488
|
+
|
489
|
+
it 'does not allow string fields to be set to Numeric' do
|
490
|
+
expect { subject.name = 1 }.to raise_error(/name/)
|
491
|
+
end
|
492
|
+
|
493
|
+
it 'does not allow a repeated field is set to nil' do
|
494
|
+
expect { subject.repeated_enum = nil }.to raise_error(TypeError)
|
495
|
+
end
|
496
|
+
|
497
|
+
context '#{simple_field_name}!' do
|
498
|
+
it 'returns value of set field' do
|
499
|
+
expect(::Test::Resource.new(:name => "Joe").name!).to eq("Joe")
|
500
|
+
end
|
501
|
+
|
502
|
+
it 'returns value of set field with default' do
|
503
|
+
expect(::Test::Resource.new(:name => "").name!).to eq("")
|
504
|
+
end
|
505
|
+
|
506
|
+
it 'returns nil if extension field is unset' do
|
507
|
+
expect(subject.ext_is_searchable!).to be_nil
|
508
|
+
end
|
509
|
+
|
510
|
+
it 'returns value of set extension field' do
|
511
|
+
message = ::Test::Resource.new(:ext_is_searchable => true)
|
512
|
+
expect(message.ext_is_searchable!).to be(true)
|
513
|
+
end
|
514
|
+
|
515
|
+
it 'returns value of set extension field with default' do
|
516
|
+
message = ::Test::Resource.new(:ext_is_searchable => false)
|
517
|
+
expect(message.ext_is_searchable!).to be(false)
|
518
|
+
end
|
519
|
+
|
520
|
+
it 'returns nil for an unset repeated field that has only be read' do
|
521
|
+
message = ::Test::Resource.new
|
522
|
+
expect(message.repeated_enum!).to be_nil
|
523
|
+
message.repeated_enum
|
524
|
+
expect(message.repeated_enum!).to be_nil
|
525
|
+
end
|
526
|
+
|
527
|
+
it 'returns value for an unset repeated field has been read and appended to' do
|
528
|
+
message = ::Test::Resource.new
|
529
|
+
message.repeated_enum << 1
|
530
|
+
expect(message.repeated_enum!).to eq([1])
|
531
|
+
end
|
532
|
+
|
533
|
+
it 'returns value for an unset repeated field has been explicitly set' do
|
534
|
+
message = ::Test::Resource.new
|
535
|
+
message.repeated_enum = [1]
|
536
|
+
expect(message.repeated_enum!).to eq([1])
|
537
|
+
end
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
describe '.get_extension_field' do
|
542
|
+
it 'fetches an extension field by its tag' do
|
543
|
+
field = ::Test::Resource.get_extension_field(100)
|
544
|
+
expect(field).to be_a(::Protobuf::Field::BoolField)
|
545
|
+
expect(field.tag).to eq(100)
|
546
|
+
expect(field.name).to eq(:ext_is_searchable)
|
547
|
+
expect(field.fully_qualified_name).to eq(:'.test.Searchable.ext_is_searchable')
|
548
|
+
expect(field).to be_extension
|
549
|
+
end
|
550
|
+
|
551
|
+
it 'fetches an extension field by its symbolized name' do
|
552
|
+
expect(::Test::Resource.get_extension_field(:ext_is_searchable)).to be_a(::Protobuf::Field::BoolField)
|
553
|
+
expect(::Test::Resource.get_extension_field('ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
|
554
|
+
expect(::Test::Resource.get_extension_field(:'.test.Searchable.ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
|
555
|
+
expect(::Test::Resource.get_extension_field('.test.Searchable.ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
|
556
|
+
end
|
557
|
+
|
558
|
+
it 'returns nil when attempting to get a non-extension field' do
|
559
|
+
expect(::Test::Resource.get_extension_field(1)).to be_nil
|
560
|
+
end
|
561
|
+
|
562
|
+
it 'returns nil when field is not found' do
|
563
|
+
expect(::Test::Resource.get_extension_field(-1)).to be_nil
|
564
|
+
expect(::Test::Resource.get_extension_field(nil)).to be_nil
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
describe '#field?' do
|
569
|
+
it 'returns false for non-existent field' do
|
570
|
+
expect(::Test::Resource.get_field('doesnotexist')).to be_nil
|
571
|
+
expect(::Test::Resource.new.field?('doesnotexist')).to be(false)
|
572
|
+
end
|
573
|
+
|
574
|
+
it 'returns false for unset field' do
|
575
|
+
expect(::Test::Resource.get_field('name')).to be
|
576
|
+
expect(::Test::Resource.new.field?('name')).to be(false)
|
577
|
+
end
|
578
|
+
|
579
|
+
it 'returns false for unset field from tag' do
|
580
|
+
expect(::Test::Resource.get_field(1)).to be
|
581
|
+
expect(::Test::Resource.new.field?(1)).to be(false)
|
582
|
+
end
|
583
|
+
|
584
|
+
it 'returns true for set field' do
|
585
|
+
expect(::Test::Resource.new(:name => "Joe").field?('name')).to be(true)
|
586
|
+
end
|
587
|
+
|
588
|
+
it 'returns true for set field with default' do
|
589
|
+
expect(::Test::Resource.new(:name => "").field?('name')).to be(true)
|
590
|
+
end
|
591
|
+
|
592
|
+
it 'returns true from field tag value' do
|
593
|
+
expect(::Test::Resource.new(:name => "Joe").field?(1)).to be(true)
|
594
|
+
end
|
595
|
+
|
596
|
+
it 'returns false for unset extension field' do
|
597
|
+
ext_field = :".test.Searchable.ext_is_searchable"
|
598
|
+
expect(::Test::Resource.get_extension_field(ext_field)).to be
|
599
|
+
expect(::Test::Resource.new.field?(ext_field)).to be(false)
|
600
|
+
end
|
601
|
+
|
602
|
+
it 'returns false for unset extension field from tag' do
|
603
|
+
expect(::Test::Resource.get_extension_field(100)).to be
|
604
|
+
expect(::Test::Resource.new.field?(100)).to be(false)
|
605
|
+
end
|
606
|
+
|
607
|
+
it 'returns true for set extension field' do
|
608
|
+
ext_field = :".test.Searchable.ext_is_searchable"
|
609
|
+
message = ::Test::Resource.new(ext_field => true)
|
610
|
+
expect(message.field?(ext_field)).to be(true)
|
611
|
+
end
|
612
|
+
|
613
|
+
it 'returns true for set extension field with default' do
|
614
|
+
ext_field = :".test.Searchable.ext_is_searchable"
|
615
|
+
message = ::Test::Resource.new(ext_field => false)
|
616
|
+
expect(message.field?(ext_field)).to be(true)
|
617
|
+
end
|
618
|
+
|
619
|
+
it 'returns true for set extension field from tag' do
|
620
|
+
ext_field = :".test.Searchable.ext_is_searchable"
|
621
|
+
message = ::Test::Resource.new(ext_field => false)
|
622
|
+
expect(message.field?(100)).to be(true)
|
623
|
+
end
|
624
|
+
|
625
|
+
it 'returns false for repeated field that has been read from' do
|
626
|
+
message = ::Test::Resource.new
|
627
|
+
expect(message.field?(:repeated_enum)).to be(false)
|
628
|
+
message.repeated_enum
|
629
|
+
expect(message.field?(:repeated_enum)).to be(false)
|
630
|
+
end
|
631
|
+
|
632
|
+
it 'returns true for a repeated field that has been read from and appended to' do
|
633
|
+
message = ::Test::Resource.new
|
634
|
+
message.repeated_enum << 1
|
635
|
+
expect(message.field?(:repeated_enum)).to be(true)
|
636
|
+
end
|
637
|
+
|
638
|
+
it 'returns true for a repeated field that has been set with the setter' do
|
639
|
+
message = ::Test::Resource.new
|
640
|
+
message.repeated_enum = [1]
|
641
|
+
expect(message.field?(:repeated_enum)).to be(true)
|
642
|
+
end
|
643
|
+
|
644
|
+
it 'returns false for a repeated field that has been replaced with []' do
|
645
|
+
message = ::Test::Resource.new
|
646
|
+
message.repeated_enum.replace([])
|
647
|
+
expect(message.field?(:repeated_enum)).to be(false)
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
describe '.get_field' do
|
652
|
+
it 'fetches a non-extension field by its tag' do
|
653
|
+
field = ::Test::Resource.get_field(1)
|
654
|
+
expect(field).to be_a(::Protobuf::Field::StringField)
|
655
|
+
expect(field.tag).to eq(1)
|
656
|
+
expect(field.name).to eq(:name)
|
657
|
+
expect(field.fully_qualified_name).to eq(:name)
|
658
|
+
expect(field).not_to be_extension
|
659
|
+
end
|
660
|
+
|
661
|
+
it 'fetches a non-extension field by its symbolized name' do
|
662
|
+
expect(::Test::Resource.get_field(:name)).to be_a(::Protobuf::Field::StringField)
|
663
|
+
expect(::Test::Resource.get_field('name')).to be_a(::Protobuf::Field::StringField)
|
664
|
+
end
|
665
|
+
|
666
|
+
it 'fetches an extension field when forced' do
|
667
|
+
expect(::Test::Resource.get_field(100, true)).to be_a(::Protobuf::Field::BoolField)
|
668
|
+
expect(::Test::Resource.get_field(:'.test.Searchable.ext_is_searchable', true)).to be_a(::Protobuf::Field::BoolField)
|
669
|
+
expect(::Test::Resource.get_field('.test.Searchable.ext_is_searchable', true)).to be_a(::Protobuf::Field::BoolField)
|
670
|
+
end
|
671
|
+
|
672
|
+
it 'returns nil when attempting to get an extension field' do
|
673
|
+
expect(::Test::Resource.get_field(100)).to be_nil
|
674
|
+
end
|
675
|
+
|
676
|
+
it 'returns nil when field is not defined' do
|
677
|
+
expect(::Test::Resource.get_field(-1)).to be_nil
|
678
|
+
expect(::Test::Resource.get_field(nil)).to be_nil
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
describe 'defining a field' do
|
683
|
+
# Case 1
|
684
|
+
context 'single base field' do
|
685
|
+
let(:klass) do
|
686
|
+
Class.new(Protobuf::Message) do
|
687
|
+
optional :string, :foo, 1
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
it 'has an accessor for foo' do
|
692
|
+
message = klass.new(:foo => 'bar')
|
693
|
+
expect(message.foo).to eq('bar')
|
694
|
+
expect(message[:foo]).to eq('bar')
|
695
|
+
expect(message['foo']).to eq('bar')
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
# Case 2
|
700
|
+
context 'base field and extension field name collision' do
|
701
|
+
let(:klass) do
|
702
|
+
Class.new(Protobuf::Message) do
|
703
|
+
optional :string, :foo, 1
|
704
|
+
optional :string, :".boom.foo", 2, :extension => true
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
it 'has an accessor for foo that refers to the base field' do
|
709
|
+
message = klass.new(:foo => 'bar', '.boom.foo' => 'bam')
|
710
|
+
expect(message.foo).to eq('bar')
|
711
|
+
expect(message[:foo]).to eq('bar')
|
712
|
+
expect(message['foo']).to eq('bar')
|
713
|
+
expect(message[:'.boom.foo']).to eq('bam')
|
714
|
+
expect(message['.boom.foo']).to eq('bam')
|
715
|
+
end
|
716
|
+
end
|
717
|
+
|
718
|
+
# Case 3
|
719
|
+
context 'no base field with extension fields with name collision' do
|
720
|
+
let(:klass) do
|
721
|
+
Class.new(Protobuf::Message) do
|
722
|
+
optional :string, :".boom.foo", 2, :extension => true
|
723
|
+
optional :string, :".goat.foo", 3, :extension => true
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
it 'has an accessor for foo that refers to the extension field' do
|
728
|
+
message = klass.new('.boom.foo' => 'bam', '.goat.foo' => 'red')
|
729
|
+
expect { message.foo }.to raise_error(NoMethodError)
|
730
|
+
expect { message[:foo] }.to raise_error(ArgumentError)
|
731
|
+
expect { message['foo'] }.to raise_error(ArgumentError)
|
732
|
+
expect(message[:'.boom.foo']).to eq('bam')
|
733
|
+
expect(message['.boom.foo']).to eq('bam')
|
734
|
+
expect(message[:'.goat.foo']).to eq('red')
|
735
|
+
expect(message['.goat.foo']).to eq('red')
|
736
|
+
end
|
737
|
+
end
|
738
|
+
|
739
|
+
# Case 4
|
740
|
+
context 'no base field with an extension field' do
|
741
|
+
let(:klass) do
|
742
|
+
Class.new(Protobuf::Message) do
|
743
|
+
optional :string, :".boom.foo", 2, :extension => true
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
it 'has an accessor for foo that refers to the extension field' do
|
748
|
+
message = klass.new('.boom.foo' => 'bam')
|
749
|
+
expect(message.foo).to eq('bam')
|
750
|
+
expect(message[:foo]).to eq('bam')
|
751
|
+
expect(message['foo']).to eq('bam')
|
752
|
+
expect(message[:'.boom.foo']).to eq('bam')
|
753
|
+
expect(message['.boom.foo']).to eq('bam')
|
754
|
+
end
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
758
|
+
describe 'map fields' do
|
759
|
+
it 'serializes the same as equivalent non-map-field' do
|
760
|
+
class MessageWithMapField < ::Protobuf::Message
|
761
|
+
map :int32, :string, :map, 1
|
762
|
+
end
|
763
|
+
|
764
|
+
class MessageWithoutMapField < ::Protobuf::Message
|
765
|
+
class MapEntry < ::Protobuf::Message
|
766
|
+
optional :int32, :key, 1
|
767
|
+
optional :string, :value, 2
|
768
|
+
end
|
769
|
+
repeated MapEntry, :map, 1
|
770
|
+
end
|
771
|
+
|
772
|
+
map_msg = MessageWithMapField.new(:map =>
|
773
|
+
{
|
774
|
+
1 => 'one',
|
775
|
+
2 => 'two',
|
776
|
+
3 => 'three',
|
777
|
+
4 => 'four',
|
778
|
+
})
|
779
|
+
mapless_msg = MessageWithoutMapField.new(:map =>
|
780
|
+
[{ :key => 1, :value => 'one' },
|
781
|
+
{ :key => 2, :value => 'two' },
|
782
|
+
{ :key => 3, :value => 'three' },
|
783
|
+
{ :key => 4, :value => 'four' },
|
784
|
+
])
|
785
|
+
|
786
|
+
map_bytes = map_msg.encode
|
787
|
+
mapless_bytes = mapless_msg.encode
|
788
|
+
expect(map_bytes).to eq(mapless_bytes)
|
789
|
+
|
790
|
+
expect(MessageWithMapField.decode(mapless_bytes)).to eq(map_msg)
|
791
|
+
expect(MessageWithoutMapField.decode(map_bytes)).to eq(mapless_msg)
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
describe '.[]=' do
|
796
|
+
context 'clearing fields' do
|
797
|
+
it 'clears repeated fields with an empty array' do
|
798
|
+
instance = ::Test::Resource.new(:repeated_enum => [::Test::StatusType::ENABLED])
|
799
|
+
expect(instance.field?(:repeated_enum)).to be(true)
|
800
|
+
instance[:repeated_enum] = []
|
801
|
+
expect(instance.field?(:repeated_enum)).to be(false)
|
802
|
+
end
|
803
|
+
|
804
|
+
it 'clears optional fields with nil' do
|
805
|
+
instance = ::Test::Resource.new(:name => "Joe")
|
806
|
+
expect(instance.field?(:name)).to be(true)
|
807
|
+
instance[:name] = nil
|
808
|
+
expect(instance.field?(:name)).to be(false)
|
809
|
+
end
|
810
|
+
|
811
|
+
it 'clears optional extenstion fields with nil' do
|
812
|
+
instance = ::Test::Resource.new(:ext_is_searchable => true)
|
813
|
+
expect(instance.field?(:ext_is_searchable)).to be(true)
|
814
|
+
instance[:ext_is_searchable] = nil
|
815
|
+
expect(instance.field?(:ext_is_searchable)).to be(false)
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
context 'setting fields' do
|
820
|
+
let(:instance) { ::Test::Resource.new }
|
821
|
+
|
822
|
+
it 'sets and replaces repeated fields' do
|
823
|
+
initial = [::Test::StatusType::ENABLED, ::Test::StatusType::DISABLED]
|
824
|
+
instance[:repeated_enum] = initial
|
825
|
+
expect(instance[:repeated_enum]).to eq(initial)
|
826
|
+
replacement = [::Test::StatusType::DELETED]
|
827
|
+
instance[:repeated_enum] = replacement
|
828
|
+
expect(instance[:repeated_enum]).to eq(replacement)
|
829
|
+
end
|
830
|
+
|
831
|
+
it 'sets acceptable optional field values' do
|
832
|
+
instance[:name] = "Joe"
|
833
|
+
expect(instance[:name]).to eq("Joe")
|
834
|
+
instance[1] = "Tom"
|
835
|
+
expect(instance[:name]).to eq("Tom")
|
836
|
+
end
|
837
|
+
|
838
|
+
it 'sets acceptable empty string field values' do
|
839
|
+
instance[:name] = ""
|
840
|
+
expect(instance.name!).to eq("")
|
841
|
+
end
|
842
|
+
|
843
|
+
it 'sets acceptable empty message field values' do
|
844
|
+
instance = ::Test::Nested.new
|
845
|
+
instance[:resource] = {}
|
846
|
+
expect(instance.resource!).to eq(::Test::Resource.new)
|
847
|
+
end
|
848
|
+
|
849
|
+
it 'sets acceptable extension field values' do
|
850
|
+
instance[:ext_is_searchable] = true
|
851
|
+
expect(instance[:ext_is_searchable]).to eq(true)
|
852
|
+
instance[:".test.Searchable.ext_is_searchable"] = false
|
853
|
+
expect(instance[:ext_is_searchable]).to eq(false)
|
854
|
+
instance[100] = true
|
855
|
+
expect(instance[:ext_is_searchable]).to eq(true)
|
856
|
+
end
|
857
|
+
|
858
|
+
# to be deprecated
|
859
|
+
it 'does nothing when sent an empty array' do
|
860
|
+
instance[:repeated_enum] = nil
|
861
|
+
expect(instance[:repeated_enum]).to eq([])
|
862
|
+
instance[:repeated_enum] = [1, 2]
|
863
|
+
expect(instance[:repeated_enum]).to eq([1, 2])
|
864
|
+
instance[:repeated_enum] = nil
|
865
|
+
# Yes this is very silly, but backwards compatible
|
866
|
+
expect(instance[:repeated_enum]).to eq([1, 2])
|
867
|
+
end
|
868
|
+
end
|
869
|
+
|
870
|
+
context 'throwing TypeError' do
|
871
|
+
let(:instance) { ::Test::Resource.new }
|
872
|
+
|
873
|
+
it 'throws when a repeated value is set with a non array' do
|
874
|
+
expect { instance[:repeated_enum] = "string" }.to raise_error(TypeError)
|
875
|
+
end
|
876
|
+
|
877
|
+
it 'throws when a repeated value is set with an array of the wrong type' do
|
878
|
+
expect { instance[:repeated_enum] = [true, false] }.to raise_error(TypeError)
|
879
|
+
end
|
880
|
+
|
881
|
+
it 'throws when an optional value is not #acceptable?' do
|
882
|
+
expect { instance[:name] = 1 }.to raise_error(TypeError)
|
883
|
+
end
|
884
|
+
end
|
885
|
+
|
886
|
+
context 'ignoring unknown fields' do
|
887
|
+
around do |example|
|
888
|
+
orig = ::Protobuf.ignore_unknown_fields?
|
889
|
+
::Protobuf.ignore_unknown_fields = true
|
890
|
+
example.call
|
891
|
+
::Protobuf.ignore_unknown_fields = orig
|
892
|
+
end
|
893
|
+
|
894
|
+
context 'with valid fields' do
|
895
|
+
let(:values) { { :name => "Jim" } }
|
896
|
+
|
897
|
+
it "does not raise an error" do
|
898
|
+
expect { ::Test::Resource.new(values) }.to_not raise_error
|
899
|
+
end
|
900
|
+
end
|
901
|
+
|
902
|
+
context 'with non-existent field' do
|
903
|
+
let(:values) { { :name => "Jim", :othername => "invalid" } }
|
904
|
+
|
905
|
+
it "does not raise an error" do
|
906
|
+
expect { ::Test::Resource.new(values) }.to_not raise_error
|
907
|
+
end
|
908
|
+
end
|
909
|
+
end
|
910
|
+
|
911
|
+
context 'not ignoring unknown fields' do
|
912
|
+
around do |example|
|
913
|
+
orig = ::Protobuf.ignore_unknown_fields?
|
914
|
+
::Protobuf.ignore_unknown_fields = false
|
915
|
+
example.call
|
916
|
+
::Protobuf.ignore_unknown_fields = orig
|
917
|
+
end
|
918
|
+
|
919
|
+
context 'with valid fields' do
|
920
|
+
let(:values) { { :name => "Jim" } }
|
921
|
+
|
922
|
+
it "does not raise an error" do
|
923
|
+
expect { ::Test::Resource.new(values) }.to_not raise_error
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
context 'with non-existent field' do
|
928
|
+
let(:values) { { :name => "Jim", :othername => "invalid" } }
|
929
|
+
|
930
|
+
it "raises an error and mentions the erroneous field" do
|
931
|
+
expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
|
932
|
+
end
|
933
|
+
|
934
|
+
context 'with a nil value' do
|
935
|
+
let(:values) { { :name => "Jim", :othername => nil } }
|
936
|
+
|
937
|
+
it "raises an error and mentions the erroneous field" do
|
938
|
+
expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
|
939
|
+
end
|
940
|
+
end
|
941
|
+
end
|
942
|
+
end
|
943
|
+
end
|
944
|
+
end
|