sparsam 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,304 @@
1
+ # -*- coding: UTF-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'rspec'
5
+ require 'json'
6
+
7
+ RSpec.configure do |configuration|
8
+ configuration.before(:each) do
9
+ end
10
+ end
11
+
12
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'gen-ruby')
13
+
14
+ require 'sparsam'
15
+ require 'user_types'
16
+ serialized = "\x15\x14\x18\x10woohoo blackbird\x1C\x15\xC8\x01\x18\bsubdata!\x00\x1A<\x15"\
17
+ "\x02\x18\fid_s default\x00\x15\x04\x18\fid_s default\x00\x15\x06\x18\fid_s "\
18
+ "default\x00+\x02X\x02\x03one\x04\x03two,\x15\xD0\x0F\x00\x00"
19
+ serialized_binary = "\b\x00\x01\x00\x00\x00\n\v\x00\x02\x00\x00\x00\x10woohoo blackbird\f\x00"\
20
+ "\x03\b\x00\x01\x00\x00\x00d\v\x00\x02\x00\x00\x00\bsubdata!\x00\x0E\x00"\
21
+ "\x04\f\x00\x00\x00\x03\b\x00\x01\x00\x00\x00\x01\v\x00\x02\x00\x00\x00\f"\
22
+ "id_s default\x00\b\x00\x01\x00\x00\x00\x02\v\x00\x02\x00\x00\x00\fid_s defaul"\
23
+ "t\x00\b\x00\x01\x00\x00\x00\x03\v\x00\x02\x00\x00\x00\fid_s default\x00\r\x00"\
24
+ "\x06\b\v\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03one\x00\x00\x00\x02"\
25
+ "\x00\x00\x00\x03two\f\x00\b\b\x00\x01\x00\x00\x03\xE8\x00\x00"
26
+
27
+ describe 'Sparsam' do
28
+ describe Sparsam::Serializer do
29
+ it "respect default values" do
30
+ subdata = US.new
31
+ subdata.id_s.should == "id_s default"
32
+ end
33
+
34
+ it "can serialize structs" do
35
+ data = SS.new
36
+ data.id_i32 = 10
37
+ data.id_s = "woohoo blackbird"
38
+ subdata = US.new
39
+ subdata.id_i32 = 100
40
+ subdata.id_s = "subdata!"
41
+ data.us_i = subdata
42
+ data.us_s = Set.new
43
+ data.us_s.add(US.new({ "id_i32" => 1 }))
44
+ data.us_s.add(US.new({ "id_i32" => 2 }))
45
+ data.us_s.add(US.new({ "id_i32" => 3 }))
46
+ data.mappy = {}
47
+ data.mappy[1] = "one"
48
+ data.mappy[2] = "two"
49
+ data.un_field = UN.new({ :id_i32 => 1000 })
50
+ result = data.serialize
51
+ Sparsam.validate(SS, data, Sparsam::RECURSIVE).should == true
52
+ result.force_encoding("BINARY").should == serialized.force_encoding("BINARY")
53
+ end
54
+
55
+ it "can handle utf-8 strings" do
56
+ data = SS.new
57
+ data.id_s = "中国电信"
58
+ result = data.serialize
59
+ data2 = Sparsam::Deserializer.deserialize(SS, result)
60
+ data2.id_s.encoding.should == data.id_s.encoding
61
+ data2.id_s.should == data.id_s
62
+ end
63
+
64
+ it "can deserialize structs" do
65
+ data = Sparsam::Deserializer.deserialize(SS, serialized)
66
+ data.id_i32.should == 10
67
+ data.id_s.should == "woohoo blackbird"
68
+ data.mappy[1].should == "one"
69
+ data.mappy[2].should == "two"
70
+ data.us_i.id_i32.should == 100
71
+ data.us_i.id_s.should == "subdata!"
72
+ data.un_field.id_i32.should == 1000
73
+ data.us_s.size.should == 3
74
+ ids = Set.new([1, 2, 3])
75
+ data.us_s.each { |val|
76
+ ids.delete(val.id_i32)
77
+ val.id_s.should == "id_s default"
78
+ }
79
+ ids.size.should == 0
80
+ end
81
+
82
+ it "can handle passing in initialization data" do
83
+ init = { "id_i32" => 10, "id_s" => "woohoo blackbird" }
84
+ data = SS.new(init)
85
+ data.id_i32.should == 10
86
+ data.id_s.should == "woohoo blackbird"
87
+ end
88
+
89
+ it "will throw exceptions when strict validation received a non-conforming type" do
90
+ data = EasilyInvalid.new
91
+ data.tail = SS.new
92
+ expect {
93
+ Sparsam.validate(NotSS, data, Sparsam::STRICT)
94
+ }.to raise_error(Sparsam::TypeMismatch)
95
+ expect {
96
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
97
+ }.to raise_error(Sparsam::TypeMismatch)
98
+
99
+ data = EasilyInvalid.new
100
+ data.s_self = Set.new([EasilyInvalid.new, SS.new])
101
+ expect {
102
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
103
+ }.to raise_error(Sparsam::TypeMismatch)
104
+
105
+ data = EasilyInvalid.new
106
+ data.l_self = [EasilyInvalid.new, SS.new]
107
+ expect {
108
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
109
+ }.to raise_error(Sparsam::TypeMismatch)
110
+
111
+ data = EasilyInvalid.new
112
+ data.mappy1 = { SS.new => 123 }
113
+ expect {
114
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
115
+ }.to raise_error(Sparsam::TypeMismatch)
116
+
117
+ data = EasilyInvalid.new
118
+ data.mappy2 = { 123 => SS.new }
119
+ expect {
120
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
121
+ }.to raise_error(Sparsam::TypeMismatch)
122
+
123
+ data = EasilyInvalid.new
124
+ data.mappy3 = { SS.new => SS.new }
125
+ expect {
126
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
127
+ }.to raise_error(Sparsam::TypeMismatch)
128
+
129
+ data = EasilyInvalid.new
130
+ data.mappy3 = { EasilyInvalid.new => SS.new }
131
+ expect {
132
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
133
+ }.to raise_error(Sparsam::TypeMismatch)
134
+
135
+ data = EasilyInvalid.new
136
+ data.mappy3 = { SS.new => EasilyInvalid.new }
137
+ expect {
138
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
139
+ }.to raise_error(Sparsam::TypeMismatch)
140
+
141
+ data = EasilyInvalid.new
142
+ data.mappy3 = { EasilyInvalid.new => EasilyInvalid.new, SS.new => EasilyInvalid.new }
143
+ expect {
144
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
145
+ }.to raise_error(Sparsam::TypeMismatch)
146
+
147
+ data = EasilyInvalid.new
148
+ data.id_i32 = "I'm pretty sure this is not an I32 LOL"
149
+ expect {
150
+ Sparsam.validate(EasilyInvalid, data, Sparsam::STRICT)
151
+ }.to raise_error(Sparsam::TypeMismatch)
152
+ end
153
+
154
+ it "works with crazy thriftness" do
155
+ data = EasilyInvalid.new
156
+ data.sure = [{ Set.new([1]) => { 1 => Set.new([[{ EasilyInvalid.new => "sure" }]]) } }]
157
+ Sparsam.validate(EasilyInvalid, data, Sparsam::RECURSIVE).should == true
158
+
159
+ data = EasilyInvalid.new
160
+ data.sure = [{ Set.new([1]) => { 1 => Set.new([[{ EasilyInvalid.new => 123 }]]) } }]
161
+ expect {
162
+ Sparsam.validate(EasilyInvalid, data, Sparsam::RECURSIVE)
163
+ }.to raise_error(Sparsam::TypeMismatch)
164
+ end
165
+
166
+ it "will throw exceptions when recursive validation is passed wrong data" do
167
+ data = EasilyInvalid.new
168
+ data.required_stuff = MiniRequired.new
169
+ expect {
170
+ Sparsam.validate(EasilyInvalid, data, Sparsam::RECURSIVE)
171
+ }.to raise_error(Sparsam::MissingMandatory)
172
+
173
+ data = EasilyInvalid.new
174
+ data.tail = EasilyInvalid.new
175
+ data.tail.s_self = Set.new([SS.new])
176
+ expect {
177
+ Sparsam.validate(EasilyInvalid, data, Sparsam::RECURSIVE)
178
+ }.to raise_error(Sparsam::TypeMismatch)
179
+ end
180
+
181
+ it "will throw exceptions when passed data that doesn't match type" do
182
+ data = SS.new
183
+ data.id_i32 = "I am not an int"
184
+ expect { data.serialize }.to raise_error(StandardError)
185
+ end
186
+
187
+ it "will validate required fields" do
188
+ data = MiniRequired.new
189
+ expect { data.validate }.to raise_error(Sparsam::MissingMandatory)
190
+ end
191
+
192
+ it "will throw errors when given junk data" do
193
+ expect {
194
+ Sparsam::Deserializer.deserialize(SS, "wolololololol")
195
+ }.to raise_error(Sparsam::Exception)
196
+ end
197
+
198
+ it "will throw errors when deserializing data with incorrect types" do
199
+ # SS expects field 1 to be an INT
200
+ # this is a struct w/ field 1 as a STRING instead
201
+ data = NotSS.new
202
+ data.id_s = "I am not an INT"
203
+ bad_type = data.serialize
204
+ expect {
205
+ Sparsam::Deserializer.deserialize(SS, bad_type)
206
+ }.to raise_error(Sparsam::TypeMismatch)
207
+ end
208
+
209
+ it "can deserialize objects with fields it doesn't know about" do
210
+ # NotSS_plus is NotSS with additional fields
211
+ # Thrift should ignore the additional fields
212
+ data = NotSS_plus.new
213
+ data.id_s = "This is ok"
214
+ data.id_s2 = "This is also ok"
215
+ data.id_i32 = 100
216
+ ser = data.serialize
217
+ notss = Sparsam::Deserializer.deserialize(NotSS, ser)
218
+ notss.id_s.should == "This is ok"
219
+ notss.id_i32.should == 100
220
+ Sparsam::Deserializer.deserialize(Nothing, ser)
221
+ end
222
+
223
+ it 'only allows one field to be set in a union' do
224
+ expect {
225
+ UN.new({ :id_i32 => 1000, :id_s => "woops" })
226
+ }.to raise_error(Sparsam::UnionException)
227
+
228
+ d = UN.new({ :id_i32 => 1000 })
229
+ d.id_s = "woops"
230
+ d.id_s
231
+
232
+ expect {
233
+ d.id_i32
234
+ }.to raise_error(Sparsam::UnionException)
235
+
236
+ d.instance_variables.should eq([:@setfield, :@id_s])
237
+ end
238
+
239
+ it 'handles empty arrays' do
240
+ data = SS.new
241
+ data.mappy = {}
242
+ data.us_s = Set.new
243
+ ser = data.serialize
244
+ unser = Sparsam::Deserializer.deserialize(SS, ser)
245
+ unser.mappy.size.should == 0
246
+ unser.us_s.size.should == 0
247
+ end
248
+
249
+ it "can serialize structs with binary" do
250
+ data = SS.new
251
+ data.id_i32 = 10
252
+ data.id_s = "woohoo blackbird"
253
+ data.mappy = {}
254
+ data.mappy[1] = "one"
255
+ data.mappy[2] = "two"
256
+ subdata = US.new
257
+ subdata.id_i32 = 100
258
+ subdata.id_s = "subdata!"
259
+ data.us_i = subdata
260
+ data.us_s = Set.new
261
+ data.us_s.add(US.new({ "id_i32" => 1 }))
262
+ data.us_s.add(US.new({ "id_i32" => 2 }))
263
+ data.us_s.add(US.new({ "id_i32" => 3 }))
264
+ data.un_field = UN.new({ :id_i32 => 1000 })
265
+ result = data.serialize(Sparsam::BinaryProtocol)
266
+ result.force_encoding("BINARY").should == serialized_binary.force_encoding("BINARY")
267
+ end
268
+
269
+ it "can deserialize structs with binary" do
270
+ data = Sparsam::Deserializer.deserialize(SS, serialized_binary, Sparsam::BinaryProtocol)
271
+ data.id_i32.should == 10
272
+ data.id_s.should == "woohoo blackbird"
273
+ data.mappy[1].should == "one"
274
+ data.mappy[2].should == "two"
275
+ data.mappy.size.should == 2
276
+ data.us_i.id_i32.should == 100
277
+ data.us_i.id_s.should == "subdata!"
278
+ data.un_field.id_i32.should == 1000
279
+ data.us_s.size.should == 3
280
+ ids = Set.new([1, 2, 3])
281
+ data.us_s.each { |val|
282
+ ids.delete(val.id_i32)
283
+ val.id_s.should == "id_s default"
284
+ }
285
+ ids.size.should == 0
286
+ end
287
+
288
+ it "can handle nested collections like a boss" do
289
+ data = SS.new
290
+ data.troll = {}
291
+ data.troll[1] = { 2 => 3 }
292
+ ser = data.serialize
293
+ new_data = Sparsam::Deserializer.deserialize(SS, ser)
294
+ new_data.troll[1][2].should == 3
295
+ end
296
+
297
+ it "doesn't segfault on malformed data" do
298
+ really_bad = "\x0f\x00\x05\x0b\x00\x00\x00\x01\x00\x00\x00\x03\x00"
299
+ expect {
300
+ Sparsam::Deserializer.deserialize(SS, really_bad, Sparsam::BinaryProtocol)
301
+ }.to raise_error(Sparsam::Exception)
302
+ end
303
+ end
304
+ end
@@ -0,0 +1,62 @@
1
+ struct US {
2
+ 1: optional i32 id_i32
3
+ 2: optional binary id_s = "id_s default"
4
+ 3: optional set<string> string_set
5
+ 4: optional set<i32> int_set
6
+ }
7
+
8
+ union UN {
9
+ 1: optional i32 id_i32
10
+ 2: optional string id_s
11
+ }
12
+
13
+ enum Magic {
14
+ Black,
15
+ White,
16
+ Red,
17
+ Blue,
18
+ Green
19
+ }
20
+
21
+ struct SS {
22
+ 1: optional i32 id_i32
23
+ 2: optional string id_s
24
+ 3: optional US us_i
25
+ 4: optional set<US> us_s
26
+ 5: optional list<string> s_l
27
+ 6: optional map<i32, string> mappy
28
+ 7: optional byte byte_field
29
+ 8: optional UN un_field
30
+ 9: optional Magic magic_field
31
+ 10: optional map<i32, map<i32, i32>> troll
32
+ }
33
+
34
+ struct MiniRequired {
35
+ 1: i32 id_i32
36
+ }
37
+
38
+ struct EasilyInvalid {
39
+ 1: optional EasilyInvalid tail
40
+ 2: optional set<EasilyInvalid> s_self
41
+ 3: optional list<EasilyInvalid> l_self
42
+ 4: optional map<EasilyInvalid, i32> mappy1
43
+ 5: optional map<i32, EasilyInvalid> mappy2
44
+ 6: optional map<EasilyInvalid, EasilyInvalid> mappy3
45
+ 7: optional list<map<set<i32>, map<i32, set<list<map<EasilyInvalid, string>>>>>> sure
46
+ 8: optional MiniRequired required_stuff
47
+ 9: optional i32 id_i32
48
+ }
49
+
50
+ struct NotSS {
51
+ 1: optional string id_s
52
+ 3: optional i32 id_i32
53
+ }
54
+
55
+ struct NotSS_plus {
56
+ 1: optional string id_s
57
+ 2: optional string id_s2
58
+ 3: optional i32 id_i32
59
+ }
60
+
61
+ struct nothing {
62
+ }
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sparsam
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Airbnb Thrift Developers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-08-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.10.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.10.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "<"
46
+ - !ruby/object:Gem::Version
47
+ version: '11.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "<"
53
+ - !ruby/object:Gem::Version
54
+ version: '11.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.41.2
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.41.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 1.5.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 1.5.0
83
+ description: Ruby bindings for the Apache Thrift RPC system
84
+ email:
85
+ - foundation.performance-eng@airbnb.com
86
+ executables: []
87
+ extensions:
88
+ - ext/extconf.rb
89
+ extra_rdoc_files:
90
+ - README.md
91
+ - ext/ruby_hooks.c
92
+ - ext/serializer.h
93
+ - ext/third-party/sparsepp/sparsepp/spp.h
94
+ - ext/third-party/sparsepp/sparsepp/spp_config.h
95
+ - ext/third-party/sparsepp/sparsepp/spp_dlalloc.h
96
+ - ext/third-party/sparsepp/sparsepp/spp_memory.h
97
+ - ext/third-party/sparsepp/sparsepp/spp_smartptr.h
98
+ - ext/third-party/sparsepp/sparsepp/spp_stdint.h
99
+ - ext/third-party/sparsepp/sparsepp/spp_timer.h
100
+ - ext/third-party/sparsepp/sparsepp/spp_traits.h
101
+ - ext/third-party/sparsepp/sparsepp/spp_utils.h
102
+ - ext/extconf.rb
103
+ - ext/serializer.cpp
104
+ - lib/sparsam/base_class.rb
105
+ - lib/sparsam/deserializer.rb
106
+ - lib/sparsam/exceptions.rb
107
+ - lib/sparsam/struct.rb
108
+ - lib/sparsam/types.rb
109
+ - lib/sparsam/union.rb
110
+ - lib/sparsam.rb
111
+ files:
112
+ - README.md
113
+ - ext/extconf.rb
114
+ - ext/ruby_hooks.c
115
+ - ext/serializer.cpp
116
+ - ext/serializer.h
117
+ - ext/third-party/sparsepp/sparsepp/spp.h
118
+ - ext/third-party/sparsepp/sparsepp/spp_config.h
119
+ - ext/third-party/sparsepp/sparsepp/spp_dlalloc.h
120
+ - ext/third-party/sparsepp/sparsepp/spp_memory.h
121
+ - ext/third-party/sparsepp/sparsepp/spp_smartptr.h
122
+ - ext/third-party/sparsepp/sparsepp/spp_stdint.h
123
+ - ext/third-party/sparsepp/sparsepp/spp_timer.h
124
+ - ext/third-party/sparsepp/sparsepp/spp_traits.h
125
+ - ext/third-party/sparsepp/sparsepp/spp_utils.h
126
+ - lib/sparsam.rb
127
+ - lib/sparsam/base_class.rb
128
+ - lib/sparsam/deserializer.rb
129
+ - lib/sparsam/exceptions.rb
130
+ - lib/sparsam/struct.rb
131
+ - lib/sparsam/types.rb
132
+ - lib/sparsam/union.rb
133
+ - spec/gen-ruby/user_constants.rb
134
+ - spec/gen-ruby/user_types.rb
135
+ - spec/sparsam_spec.rb
136
+ - spec/user.thrift
137
+ homepage: http://thrift.apache.org
138
+ licenses:
139
+ - Apache 2.0
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options:
143
+ - "--line-numbers"
144
+ - "--inline-source"
145
+ - "--title"
146
+ - Thrift
147
+ - "--main"
148
+ - README
149
+ require_paths:
150
+ - lib
151
+ - ext
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ required_rubygems_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ requirements: []
163
+ rubyforge_project: thrift
164
+ rubygems_version: 2.6.12
165
+ signing_key:
166
+ specification_version: 4
167
+ summary: Ruby bindings for Apache Thrift
168
+ test_files:
169
+ - spec/gen-ruby/user_constants.rb
170
+ - spec/gen-ruby/user_types.rb
171
+ - spec/sparsam_spec.rb
172
+ - spec/user.thrift