sparsam 0.1.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.
@@ -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