protip 0.20.7 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/protip.rb +10 -0
  3. data/lib/protip/{wrapper.rb → decorator.rb} +98 -82
  4. data/lib/protip/extensions.rb +0 -1
  5. data/lib/protip/resource.rb +56 -32
  6. data/lib/protip/resource/extra_methods.rb +5 -3
  7. data/lib/protip/tasks/compile.rake +2 -2
  8. data/lib/protip/transformer.rb +14 -0
  9. data/lib/protip/transformers/abstract_transformer.rb +11 -0
  10. data/lib/protip/transformers/active_support/time_with_zone_transformer.rb +35 -0
  11. data/lib/protip/transformers/decorating_transformer.rb +33 -0
  12. data/lib/protip/transformers/default_transformer.rb +22 -0
  13. data/lib/protip/transformers/delegating_transformer.rb +44 -0
  14. data/lib/protip/transformers/deprecated_transformer.rb +90 -0
  15. data/lib/protip/transformers/enum_transformer.rb +93 -0
  16. data/lib/protip/transformers/primitives_transformer.rb +78 -0
  17. data/lib/protip/transformers/timestamp_transformer.rb +31 -0
  18. data/test/functional/protip/decorator_test.rb +204 -0
  19. data/test/unit/protip/decorator_test.rb +665 -0
  20. data/test/unit/protip/resource_test.rb +76 -92
  21. data/test/unit/protip/transformers/decorating_transformer_test.rb +92 -0
  22. data/test/unit/protip/transformers/delegating_transformer_test.rb +83 -0
  23. data/test/unit/protip/transformers/deprecated_transformer_test.rb +139 -0
  24. data/test/unit/protip/transformers/enum_transformer_test.rb +157 -0
  25. data/test/unit/protip/transformers/primitives_transformer_test.rb +139 -0
  26. data/test/unit/protip/transformers/timestamp_transformer_test.rb +46 -0
  27. metadata +23 -12
  28. data/definitions/google/protobuf/wrappers.proto +0 -99
  29. data/lib/google/protobuf/descriptor.rb +0 -1
  30. data/lib/google/protobuf/wrappers.rb +0 -48
  31. data/lib/protip/converter.rb +0 -22
  32. data/lib/protip/standard_converter.rb +0 -185
  33. data/test/unit/protip/standard_converter_test.rb +0 -502
  34. data/test/unit/protip/wrapper_test.rb +0 -646
@@ -1,502 +0,0 @@
1
- require 'test_helper'
2
- require 'money'
3
-
4
- require 'google/protobuf/wrappers'
5
- require 'protip/messages/active_support/time_with_zone'
6
- require 'protip/standard_converter'
7
- require 'protip/messages/test'
8
-
9
- describe Protip::StandardConverter do
10
- let :pool do
11
- # See https://github.com/google/protobuf/blob/master/ruby/tests/generated_code.rb for
12
- # examples of field types you can add here
13
- pool = Google::Protobuf::DescriptorPool.new
14
- pool.build do
15
- add_enum 'number' do
16
- value :ZERO, 0
17
- value :ONE, 1
18
- end
19
- end
20
- pool
21
- end
22
- let(:enum) { pool.lookup 'number' }
23
-
24
- let(:converter) { Protip::StandardConverter.new }
25
-
26
- let(:integer_types) do
27
- [
28
- Google::Protobuf::Int64Value,
29
- Google::Protobuf::Int32Value,
30
- Google::Protobuf::UInt64Value,
31
- Google::Protobuf::UInt32Value
32
- ]
33
- end
34
-
35
- let(:repeated_integer_types) do
36
- [
37
- Protip::Messages::RepeatedInt64,
38
- Protip::Messages::RepeatedInt32,
39
- Protip::Messages::RepeatedUInt64,
40
- Protip::Messages::RepeatedUInt32,
41
- ]
42
- end
43
-
44
- let(:float_types) do
45
- [
46
- Google::Protobuf::FloatValue,
47
- Google::Protobuf::DoubleValue
48
- ]
49
- end
50
-
51
- let(:repeated_float_types) do
52
- [
53
- Protip::Messages::RepeatedFloat,
54
- Protip::Messages::RepeatedDouble,
55
- ]
56
- end
57
-
58
- let(:bool_types) do
59
- [Google::Protobuf::BoolValue]
60
- end
61
-
62
- let(:repeated_bool_types) do
63
- [Protip::Messages::RepeatedBool]
64
- end
65
-
66
- let(:string_types) do
67
- [Google::Protobuf::StringValue]
68
- end
69
-
70
- let(:repeated_string_types) do
71
- [Protip::Messages::RepeatedString]
72
- end
73
-
74
- let(:bytes_types) do
75
- [Google::Protobuf::BytesValue]
76
- end
77
-
78
- let(:repeated_bytes_types) do
79
- [Protip::Messages::RepeatedBytes]
80
- end
81
-
82
- let(:protip_types) do
83
- [
84
- Protip::Messages::Range,
85
- Protip::Messages::Date,
86
- Protip::Messages::Money,
87
- Protip::Messages::Currency
88
- ]
89
- end
90
-
91
- let(:integer_value) { 6 }
92
- let(:float_value) { 5.5 }
93
- let(:bool_value) { true }
94
- let(:string_value) { 'asdf' }
95
- let(:bytes_value) { Base64.decode64("U2VuZCByZWluZm9yY2VtZW50cw==\n") }
96
-
97
- describe '#convertible?' do
98
- it 'converts all standard types' do
99
- (integer_types + float_types + string_types + bool_types + protip_types + repeated_integer_types +
100
- repeated_float_types + repeated_string_types + repeated_bool_types).each do |message_class|
101
- assert converter.convertible?(message_class), "expected type #{message_class.descriptor.name} not convertible"
102
- end
103
- end
104
-
105
- it 'does not convert other message types' do
106
- pool = Google::Protobuf::DescriptorPool.new
107
- pool.build { add_message('test_message') { optional :id, :string, 1 } }
108
- refute converter.convertible?(pool.lookup('test_message').msgclass)
109
- end
110
- end
111
-
112
- let(:field) { mock.responds_like_instance_of Google::Protobuf::FieldDescriptor }
113
-
114
- describe '#to_object' do
115
- it 'converts wrapper types' do
116
- {
117
- integer_value => integer_types,
118
- float_value => float_types,
119
- bool_value => bool_types,
120
- string_value => string_types,
121
- bytes_value => bytes_types,
122
- }.each do |value, message_types|
123
- message_types.each do |message_class|
124
- assert_equal value, converter.to_object(message_class.new(value: value), field)
125
- end
126
- end
127
- end
128
-
129
- it 'converts repeated types to an immutable array' do
130
- {
131
- integer_value => repeated_integer_types,
132
- float_value => repeated_float_types,
133
- bool_value => repeated_bool_types,
134
- string_value => repeated_string_types,
135
- bytes_value => repeated_bytes_types,
136
- }.each do |value, message_types|
137
- message_types.each do |message_class|
138
- result = converter.to_object(message_class.new(values: [value]), field)
139
- assert_equal [value], result
140
- exception = assert_raises RuntimeError do
141
- result << value
142
- end
143
- assert_equal 'can\'t modify frozen Array', exception.message
144
- end
145
- end
146
- end
147
-
148
- it 'converts dates' do
149
- date = converter.to_object(::Protip::Messages::Date.new(year: 2015, month: 2, day: 9), field)
150
- assert_instance_of ::Date, date
151
- assert_equal '2015-02-09', date.strftime
152
- end
153
-
154
- it 'converts ranges' do
155
- range = converter.to_object(::Protip::Messages::Range.new(begin: 1, end: 4), field)
156
- assert_instance_of ::Range, range
157
- assert_equal 1..4, range
158
- end
159
-
160
- it 'converts currency' do
161
- currency = converter.to_object(::Protip::Messages::Currency.new(currency_code: :GBP), field)
162
- assert_equal :GBP, currency
163
- end
164
-
165
- it 'converts money' do
166
- message = ::Protip::Messages::Money.new amount_cents: 250,
167
- currency: (::Protip::Messages::Currency.new currency_code: :CAD)
168
- money = converter.to_object(message, field)
169
- assert_instance_of ::Money, money
170
- assert_equal Money::Currency.new(:CAD), money.currency
171
- assert_equal 250, money.fractional
172
- assert_equal ::Money.new(250, 'CAD'), money
173
- end
174
-
175
- it 'converts times with zones' do
176
- message = ::Protip::Messages::ActiveSupport::TimeWithZone.new utc_timestamp: 1451610000,
177
- time_zone_name: 'America/Los_Angeles'
178
- time = converter.to_object(message, field)
179
- assert_instance_of ::ActiveSupport::TimeWithZone, time
180
- assert_equal 1451610000, time.to_i
181
- assert_equal '2015-12-31T17:00:00-08:00', time.iso8601
182
- end
183
-
184
- describe 'enums' do
185
- before do
186
- ::Protip::StandardConverter.stubs(:enum_for_field).with(field).returns(enum)
187
- end
188
-
189
- # Make sure we mirror the behavior of an actual enum field on the message.
190
- it 'converts enum values in range to symbols' do
191
- message = ::Protip::Messages::EnumValue.new value: 1
192
- assert_equal :ONE, converter.to_object(message, field)
193
- end
194
-
195
- it 'converts enum values out of range to integers' do
196
- message = ::Protip::Messages::EnumValue.new value: 5
197
- assert_equal 5, converter.to_object(message, field)
198
- end
199
-
200
- it 'converts repeated enum values in range to symbols' do
201
- message = ::Protip::Messages::RepeatedEnum.new values: [0, 1]
202
- assert_equal [:ZERO, :ONE], converter.to_object(message, field)
203
- end
204
-
205
- it 'converts repeated enum values out of range to integers' do
206
- message = ::Protip::Messages::RepeatedEnum.new values: [3, 1, 5]
207
- assert_equal [3, :ONE, 5], converter.to_object(message, field)
208
- end
209
- end
210
- end
211
-
212
- describe '.enum_for_field' do
213
- # TODO pending https://github.com/google/protobuf/issues/1198
214
- end
215
-
216
- describe '#to_message' do
217
- it 'converts wrapper types' do
218
- {
219
- integer_value => integer_types,
220
- float_value => float_types,
221
- bool_value => bool_types,
222
- string_value => string_types,
223
- bytes_value => bytes_types,
224
- }.each do |value, message_types|
225
- message_types.each do |message_class|
226
- assert_equal message_class.new(value: value), converter.to_message(value, message_class, field)
227
- end
228
- end
229
- end
230
-
231
- it 'converts wrapper types when set as a non-native type' do
232
- # Convert from string
233
- {
234
- integer_value => integer_types,
235
- float_value => float_types,
236
- bool_value => bool_types,
237
- }.each do |value, message_types|
238
- message_types.each do |message_class|
239
- assert_equal message_class.new(value: value), converter.to_message(value.to_s, message_class, field)
240
- end
241
- end
242
-
243
- # Convert from integer
244
- {
245
- '4' => string_types,
246
- }.each do |value, message_types|
247
- message_types.each do |message_class|
248
- assert_equal message_class.new(value: value), converter.to_message(value.to_i, message_class, field)
249
- end
250
- end
251
- end
252
-
253
- it 'converts repeated types when set with a scalar value' do
254
- {
255
- integer_value => repeated_integer_types,
256
- float_value => repeated_float_types,
257
- bool_value => repeated_bool_types,
258
- string_value => repeated_string_types,
259
- bytes_value => repeated_bytes_types,
260
- }.each do |value, message_types|
261
- message_types.each do |message_class|
262
- assert_equal message_class.new(values: [value]), converter.to_message(value, message_class, field)
263
- end
264
- end
265
- end
266
-
267
- it 'converts repeated types when set with a non-native scalar type' do
268
- # Convert from string
269
- {
270
- integer_value => repeated_integer_types,
271
- float_value => repeated_float_types,
272
- bool_value => repeated_bool_types,
273
- }.each do |value, message_types|
274
- message_types.each do |message_class|
275
- assert_equal message_class.new(values: [value]), converter.to_message(value.to_s, message_class, field)
276
- end
277
- end
278
-
279
- # Convert from integer
280
- {
281
- '4' => repeated_string_types,
282
- }.each do |value, message_types|
283
- message_types.each do |message_class|
284
- assert_equal message_class.new(values: [value]), converter.to_message(value.to_i, message_class, field)
285
- end
286
- end
287
-
288
- end
289
-
290
- it 'converts repeated types when set with an enumerable value' do
291
- {
292
- integer_value => repeated_integer_types,
293
- float_value => repeated_float_types,
294
- bool_value => repeated_bool_types,
295
- string_value => repeated_string_types,
296
- bytes_value => repeated_bytes_types,
297
- }.each do |value, message_types|
298
- message_types.each do |message_class|
299
- assert_equal message_class.new(values: [value, value]), converter.to_message(
300
- [value, value], message_class, field
301
- )
302
- end
303
- end
304
- end
305
-
306
- it 'converts repeated types when set with a non-native enumerable type' do
307
- # Convert from string
308
- {
309
- integer_value => repeated_integer_types,
310
- float_value => repeated_float_types,
311
- bool_value => repeated_bool_types,
312
- }.each do |value, message_types|
313
- message_types.each do |message_class|
314
- assert_equal message_class.new(values: [value, value]), converter.to_message(
315
- [value.to_s, value.to_s], message_class, field
316
- )
317
- end
318
- end
319
-
320
- # Convert from integer
321
- {
322
- '4' => repeated_string_types,
323
- }.each do |value, message_types|
324
- message_types.each do |message_class|
325
- assert_equal message_class.new(values: [value, value]), converter.to_message(
326
- [value.to_i, value.to_i], message_class, field
327
- )
328
- end
329
- end
330
-
331
- end
332
-
333
- it 'converts dates' do
334
- date = ::Date.new(2012, 5, 7)
335
- assert_equal 7, date.day # Sanity check argument order
336
- assert_equal ::Protip::Messages::Date.new(year: 2012, month: 5, day: 7), converter.to_message(date, ::Protip::Messages::Date, field)
337
- end
338
-
339
- it 'converts ranges' do
340
- range = -1..34
341
- assert_equal ::Protip::Messages::Range.new(begin: -1, end: 34), converter.to_message(range, ::Protip::Messages::Range, field)
342
- end
343
-
344
- it 'converts currency' do
345
- currency = :HKD
346
- message = converter.to_message(currency, ::Protip::Messages::Currency, field)
347
- assert_equal ::Protip::Messages::Currency.new(currency_code: currency), message
348
- end
349
-
350
- it 'converts money' do
351
- money = ::Money.new(250, 'CAD')
352
- message = converter.to_message(money, ::Protip::Messages::Money, field)
353
- assert_instance_of ::Protip::Messages::Money, message
354
- assert_equal ::Protip::Messages::Money.new(
355
- amount_cents: money.cents,
356
- currency: ::Protip::Messages::Currency.new(
357
- currency_code: money.currency.iso_code.to_sym
358
- )),
359
- message
360
- end
361
-
362
- it 'converts truthy values to booleans' do
363
- [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].each do |truth_value|
364
- assert_equal Google::Protobuf::BoolValue.new(value: true),
365
- converter.to_message(truth_value, Google::Protobuf::BoolValue, field)
366
- end
367
- end
368
-
369
- it 'converts falsey values to booleans' do
370
- [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].each do |false_value|
371
- assert_equal Google::Protobuf::BoolValue.new(value: false),
372
- converter.to_message(false_value, Google::Protobuf::BoolValue, field)
373
- end
374
- end
375
-
376
- it 'raises an exception if non-boolean values passed to boolean field' do
377
- [nil, 'test', Object.new, 2, {}, []].each do |bad_value|
378
- assert_raises TypeError do
379
- converter.to_message(bad_value, Google::Protobuf::BoolValue, field)
380
- end
381
- end
382
- end
383
-
384
- it 'converts times with zones' do
385
- time_with_zone = ::ActiveSupport::TimeWithZone.new(Time.new(2016, 1, 1, 0, 0, 0, 0),
386
- ::ActiveSupport::TimeZone.new('America/New_York'))
387
- message = converter.to_message(time_with_zone, ::Protip::Messages::ActiveSupport::TimeWithZone, field)
388
- assert_equal 1451606400, message.utc_timestamp
389
- assert_equal 'America/New_York', message.time_zone_name
390
- end
391
-
392
- it 'converts times without zones' do
393
- time = Time.new(2016, 1, 1, 0, 0, 0, -3600)
394
- message = converter.to_message(time, ::Protip::Messages::ActiveSupport::TimeWithZone, field)
395
- assert_equal 1451610000, message.utc_timestamp
396
- assert_equal 'UTC', message.time_zone_name
397
- end
398
-
399
- it 'converts datetimes without zones' do
400
- datetime = DateTime.new(2016, 1, 1, 0, 0, 0, '-1')
401
- message = converter.to_message(datetime, ::Protip::Messages::ActiveSupport::TimeWithZone, field)
402
- assert_equal 1451610000, message.utc_timestamp
403
- assert_equal 'UTC', message.time_zone_name
404
-
405
- end
406
-
407
- describe 'enums' do
408
- before do
409
- ::Protip::StandardConverter.stubs(:enum_for_field).with(field).returns(enum)
410
- end
411
- def convert(value)
412
- converter.to_message value, message_class, field
413
- end
414
- %w(zero one two).each do |number| # values symbolizing as :ZERO, :ONE, :TWO
415
- let number do
416
- value = mock
417
- value.stubs(:to_sym).returns(number.upcase.to_sym)
418
- value
419
- end
420
- end
421
-
422
- describe '::Protip::Messages::EnumValue' do
423
- let(:message_class) { ::Protip::Messages::EnumValue }
424
- # Ensure identical behavior to setting a standard enum field
425
- it 'converts integers' do
426
- assert_equal 1, convert(1).value, 'improper conversion of an in-range integer'
427
- assert_equal 4, convert(4).value, 'improper conversion of an out-of-range integer'
428
- end
429
- it 'converts non-integers via to_sym' do
430
- assert_equal 1, convert(one).value, 'improper conversion of non-integer value'
431
- end
432
- it 'throws an error when a non-existent symbol is given' do
433
- assert_raises RangeError do
434
- convert(two)
435
- end
436
- end
437
- end
438
-
439
- describe '::Protip::Messages::RepeatedEnum' do
440
- let(:message_class) { ::Protip::Messages::RepeatedEnum }
441
- it 'converts integers' do
442
- assert_equal [1, 4], convert([1, 4]).values
443
- end
444
- it 'converts non-integers via to_sym' do
445
- assert_equal [0, 2, 1], convert([zero, 2, one]).values
446
- end
447
- it 'throws an error when a non-existent symbol is given' do
448
- assert_raises RangeError do
449
- convert([0, two])
450
- end
451
- end
452
- it 'allows assigning a scalar value' do
453
- assert_equal [1], convert(one).values
454
- end
455
- end
456
- end
457
- end
458
-
459
- describe '(enums - functional)' do # Temp - test an actual compiled file to make sure our options hack is working
460
- let(:wrapped_message) { Protip::Messages::EnumTest.new }
461
- let(:wrapper) { Protip::Wrapper.new wrapped_message, converter }
462
-
463
- let(:value_map) do
464
- {
465
- :ONE => :ONE,
466
- 1 => :ONE,
467
- 2 => 2,
468
- }
469
- end
470
-
471
- it 'allows setting and getting a scalar field by Ruby value' do
472
- value_map.each do |value, expected|
473
- wrapper.enum = value
474
- assert_equal expected, wrapper.enum
475
- end
476
- assert_raises RangeError do
477
- wrapper.enum = :TWO
478
- end
479
- end
480
- it 'allows setting and getting a scalar field by message' do
481
- wrapper.enum = ::Protip::Messages::EnumValue.new(value: 1)
482
- assert_equal :ONE, wrapper.enum
483
- end
484
-
485
- it 'allows setting and getting a repeated field by Ruby value' do
486
- value_map.each do |value, expected|
487
- wrapper.repeated_enums = [value]
488
- assert_equal [expected], wrapper.repeated_enums
489
- end
490
- assert_raises RangeError do
491
- wrapper.repeated_enums = [:TWO]
492
- end
493
- end
494
- it 'allows setting and geting a repeated field by message' do
495
- wrapper.repeated_enums = ::Protip::Messages::RepeatedEnum.new(values: [2])
496
- assert_equal [2], wrapper.repeated_enums
497
- end
498
-
499
-
500
- end
501
-
502
- end