google-protobuf 3.11.3 → 3.15.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

@@ -0,0 +1,145 @@
1
+ /* Copyright 2020 王一 Wang Yi <godspeed_china@yeah.net>
2
+ This is free and unencumbered software released into the public domain. http://unlicense.org/
3
+ See github.com/wangyi-fudan/wyhash/ LICENSE
4
+ */
5
+ #ifndef wyhash_final_version
6
+ #define wyhash_final_version
7
+ //defines that change behavior
8
+ #ifndef WYHASH_CONDOM
9
+ #define WYHASH_CONDOM 1 //0: read 8 bytes before and after boundaries, dangerous but fastest. 1: normal valid behavior 2: extra protection against entropy loss (probability=2^-63), aka. "blind multiplication"
10
+ #endif
11
+ #define WYHASH_32BIT_MUM 0 //faster on 32 bit system
12
+ //includes
13
+ #include <stdint.h>
14
+ #include <string.h>
15
+ #if defined(_MSC_VER) && defined(_M_X64)
16
+ #include <intrin.h>
17
+ #pragma intrinsic(_umul128)
18
+ #endif
19
+ #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
20
+ #define _likely_(x) __builtin_expect(x,1)
21
+ #define _unlikely_(x) __builtin_expect(x,0)
22
+ #else
23
+ #define _likely_(x) (x)
24
+ #define _unlikely_(x) (x)
25
+ #endif
26
+ //mum function
27
+ static inline uint64_t _wyrot(uint64_t x) { return (x>>32)|(x<<32); }
28
+ static inline void _wymum(uint64_t *A, uint64_t *B){
29
+ #if(WYHASH_32BIT_MUM)
30
+ uint64_t hh=(*A>>32)*(*B>>32), hl=(*A>>32)*(unsigned)*B, lh=(unsigned)*A*(*B>>32), ll=(uint64_t)(unsigned)*A*(unsigned)*B;
31
+ #if(WYHASH_CONDOM>1)
32
+ *A^=_wyrot(hl)^hh; *B^=_wyrot(lh)^ll;
33
+ #else
34
+ *A=_wyrot(hl)^hh; *B=_wyrot(lh)^ll;
35
+ #endif
36
+ #elif defined(__SIZEOF_INT128__)
37
+ __uint128_t r=*A; r*=*B;
38
+ #if(WYHASH_CONDOM>1)
39
+ *A^=(uint64_t)r; *B^=(uint64_t)(r>>64);
40
+ #else
41
+ *A=(uint64_t)r; *B=(uint64_t)(r>>64);
42
+ #endif
43
+ #elif defined(_MSC_VER) && defined(_M_X64)
44
+ #if(WYHASH_CONDOM>1)
45
+ uint64_t a, b;
46
+ a=_umul128(*A,*B,&b);
47
+ *A^=a; *B^=b;
48
+ #else
49
+ *A=_umul128(*A,*B,B);
50
+ #endif
51
+ #else
52
+ uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo;
53
+ uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl;
54
+ lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c;
55
+ #if(WYHASH_CONDOM>1)
56
+ *A^=lo; *B^=hi;
57
+ #else
58
+ *A=lo; *B=hi;
59
+ #endif
60
+ #endif
61
+ }
62
+ static inline uint64_t _wymix(uint64_t A, uint64_t B){ _wymum(&A,&B); return A^B; }
63
+ //read functions
64
+ #ifndef WYHASH_LITTLE_ENDIAN
65
+ #if defined(_WIN32) || defined(__LITTLE_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
66
+ #define WYHASH_LITTLE_ENDIAN 1
67
+ #elif defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
68
+ #define WYHASH_LITTLE_ENDIAN 0
69
+ #endif
70
+ #endif
71
+ #if (WYHASH_LITTLE_ENDIAN)
72
+ static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return v;}
73
+ static inline uint64_t _wyr4(const uint8_t *p) { unsigned v; memcpy(&v, p, 4); return v;}
74
+ #elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
75
+ static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return __builtin_bswap64(v);}
76
+ static inline uint64_t _wyr4(const uint8_t *p) { unsigned v; memcpy(&v, p, 4); return __builtin_bswap32(v);}
77
+ #elif defined(_MSC_VER)
78
+ static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return _byteswap_uint64(v);}
79
+ static inline uint64_t _wyr4(const uint8_t *p) { unsigned v; memcpy(&v, p, 4); return _byteswap_ulong(v);}
80
+ #endif
81
+ static inline uint64_t _wyr3(const uint8_t *p, unsigned k) { return (((uint64_t)p[0])<<16)|(((uint64_t)p[k>>1])<<8)|p[k-1];}
82
+ //wyhash function
83
+ static inline uint64_t _wyfinish16(const uint8_t *p, uint64_t len, uint64_t seed, const uint64_t *secret, uint64_t i){
84
+ #if(WYHASH_CONDOM>0)
85
+ uint64_t a, b;
86
+ if(_likely_(i<=8)){
87
+ if(_likely_(i>=4)){ a=_wyr4(p); b=_wyr4(p+i-4); }
88
+ else if (_likely_(i)){ a=_wyr3(p,i); b=0; }
89
+ else a=b=0;
90
+ }
91
+ else{ a=_wyr8(p); b=_wyr8(p+i-8); }
92
+ return _wymix(secret[1]^len,_wymix(a^secret[1], b^seed));
93
+ #else
94
+ #define oneshot_shift ((i<8)*((8-i)<<3))
95
+ return _wymix(secret[1]^len,_wymix((_wyr8(p)<<oneshot_shift)^secret[1],(_wyr8(p+i-8)>>oneshot_shift)^seed));
96
+ #endif
97
+ }
98
+
99
+ static inline uint64_t _wyfinish(const uint8_t *p, uint64_t len, uint64_t seed, const uint64_t *secret, uint64_t i){
100
+ if(_likely_(i<=16)) return _wyfinish16(p,len,seed,secret,i);
101
+ return _wyfinish(p+16,len,_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed),secret,i-16);
102
+ }
103
+
104
+ static inline uint64_t wyhash(const void *key, uint64_t len, uint64_t seed, const uint64_t *secret){
105
+ const uint8_t *p=(const uint8_t *)key;
106
+ uint64_t i=len; seed^=*secret;
107
+ if(_unlikely_(i>64)){
108
+ uint64_t see1=seed;
109
+ do{
110
+ seed=_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed)^_wymix(_wyr8(p+16)^secret[2],_wyr8(p+24)^seed);
111
+ see1=_wymix(_wyr8(p+32)^secret[3],_wyr8(p+40)^see1)^_wymix(_wyr8(p+48)^secret[4],_wyr8(p+56)^see1);
112
+ p+=64; i-=64;
113
+ }while(i>64);
114
+ seed^=see1;
115
+ }
116
+ return _wyfinish(p,len,seed,secret,i);
117
+ }
118
+ //utility functions
119
+ static const uint64_t _wyp[5] = {0xa0761d6478bd642full, 0xe7037ed1a0b428dbull, 0x8ebc6af09c88c6e3ull, 0x589965cc75374cc3ull, 0x1d8e4e27c47d124full};
120
+ static inline uint64_t wyhash64(uint64_t A, uint64_t B){ A^=_wyp[0]; B^=_wyp[1]; _wymum(&A,&B); return _wymix(A^_wyp[0],B^_wyp[1]);}
121
+ static inline uint64_t wyrand(uint64_t *seed){ *seed+=_wyp[0]; return _wymix(*seed,*seed^_wyp[1]);}
122
+ static inline double wy2u01(uint64_t r){ const double _wynorm=1.0/(1ull<<52); return (r>>12)*_wynorm;}
123
+ static inline double wy2gau(uint64_t r){ const double _wynorm=1.0/(1ull<<20); return ((r&0x1fffff)+((r>>21)&0x1fffff)+((r>>42)&0x1fffff))*_wynorm-3.0;}
124
+ static inline uint64_t wy2u0k(uint64_t r, uint64_t k){ _wymum(&r,&k); return k; }
125
+
126
+ static inline void make_secret(uint64_t seed, uint64_t *secret){
127
+ uint8_t c[] = {15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, 57, 58, 60, 71, 75, 77, 78, 83, 85, 86, 89, 90, 92, 99, 101, 102, 105, 106, 108, 113, 114, 116, 120, 135, 139, 141, 142, 147, 149, 150, 153, 154, 156, 163, 165, 166, 169, 170, 172, 177, 178, 180, 184, 195, 197, 198, 201, 202, 204, 209, 210, 212, 216, 225, 226, 228, 232, 240 };
128
+ for(size_t i=0;i<5;i++){
129
+ uint8_t ok;
130
+ do{
131
+ ok=1; secret[i]=0;
132
+ for(size_t j=0;j<64;j+=8) secret[i]|=((uint64_t)c[wyrand(&seed)%sizeof(c)])<<j;
133
+ if(secret[i]%2==0){ ok=0; continue; }
134
+ for(size_t j=0;j<i;j++)
135
+ #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
136
+ if(__builtin_popcountll(secret[j]^secret[i])!=32){ ok=0; break; }
137
+ #elif defined(_MSC_VER) && defined(_M_X64)
138
+ if(_mm_popcnt_u64(secret[j]^secret[i])!=32){ ok=0; break; }
139
+ #endif
140
+ if(!ok)continue;
141
+ for(uint64_t j=3;j<0x100000000ull;j+=2) if(secret[i]%j==0){ ok=0; break; }
142
+ }while(!ok);
143
+ }
144
+ }
145
+ #endif
File without changes
data/tests/basic.rb CHANGED
@@ -31,12 +31,44 @@ module BasicTest
31
31
  end
32
32
  include CommonTests
33
33
 
34
+ def test_issue_8311_crash
35
+ Google::Protobuf::DescriptorPool.generated_pool.build do
36
+ add_file("inner.proto", :syntax => :proto3) do
37
+ add_message "Inner" do
38
+ # Removing either of these fixes the segfault.
39
+ optional :foo, :string, 1
40
+ optional :bar, :string, 2
41
+ end
42
+ end
43
+ end
44
+
45
+ Google::Protobuf::DescriptorPool.generated_pool.build do
46
+ add_file("outer.proto", :syntax => :proto3) do
47
+ add_message "Outer" do
48
+ repeated :inners, :message, 1, "Inner"
49
+ end
50
+ end
51
+ end
52
+
53
+ outer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Outer").msgclass
54
+
55
+ outer.new(
56
+ inners: []
57
+ )['inners'].to_s
58
+
59
+ assert_raise Google::Protobuf::TypeError do
60
+ outer.new(
61
+ inners: [nil]
62
+ ).to_s
63
+ end
64
+ end
65
+
34
66
  def test_has_field
35
- m = TestMessage.new
36
- assert !m.has_optional_msg?
37
- m.optional_msg = TestMessage2.new
38
- assert m.has_optional_msg?
39
- assert TestMessage.descriptor.lookup('optional_msg').has?(m)
67
+ m = TestSingularFields.new
68
+ assert !m.has_singular_msg?
69
+ m.singular_msg = TestMessage2.new
70
+ assert m.has_singular_msg?
71
+ assert TestSingularFields.descriptor.lookup('singular_msg').has?(m)
40
72
 
41
73
  m = OneofMessage.new
42
74
  assert !m.has_my_oneof?
@@ -45,32 +77,31 @@ module BasicTest
45
77
  assert_raise NoMethodError do
46
78
  m.has_a?
47
79
  end
48
- assert_raise ArgumentError do
49
- OneofMessage.descriptor.lookup('a').has?(m)
50
- end
80
+ assert_true OneofMessage.descriptor.lookup('a').has?(m)
51
81
 
52
- m = TestMessage.new
82
+ m = TestSingularFields.new
53
83
  assert_raise NoMethodError do
54
- m.has_optional_int32?
84
+ m.has_singular_int32?
55
85
  end
56
86
  assert_raise ArgumentError do
57
- TestMessage.descriptor.lookup('optional_int32').has?(m)
87
+ TestSingularFields.descriptor.lookup('singular_int32').has?(m)
58
88
  end
59
89
 
60
90
  assert_raise NoMethodError do
61
- m.has_optional_string?
91
+ m.has_singular_string?
62
92
  end
63
93
  assert_raise ArgumentError do
64
- TestMessage.descriptor.lookup('optional_string').has?(m)
94
+ TestSingularFields.descriptor.lookup('singular_string').has?(m)
65
95
  end
66
96
 
67
97
  assert_raise NoMethodError do
68
- m.has_optional_bool?
98
+ m.has_singular_bool?
69
99
  end
70
100
  assert_raise ArgumentError do
71
- TestMessage.descriptor.lookup('optional_bool').has?(m)
101
+ TestSingularFields.descriptor.lookup('singular_bool').has?(m)
72
102
  end
73
103
 
104
+ m = TestMessage.new
74
105
  assert_raise NoMethodError do
75
106
  m.has_repeated_msg?
76
107
  end
@@ -79,40 +110,59 @@ module BasicTest
79
110
  end
80
111
  end
81
112
 
113
+ def test_no_presence
114
+ m = TestSingularFields.new
115
+
116
+ # Explicitly setting to zero does not cause anything to be serialized.
117
+ m.singular_int32 = 0
118
+ assert_equal "", TestSingularFields.encode(m)
119
+
120
+ # Explicitly setting to a non-zero value *does* cause serialization.
121
+ m.singular_int32 = 1
122
+ assert_not_equal "", TestSingularFields.encode(m)
123
+
124
+ m.singular_int32 = 0
125
+ assert_equal "", TestSingularFields.encode(m)
126
+ end
127
+
82
128
  def test_set_clear_defaults
83
- m = TestMessage.new
129
+ m = TestSingularFields.new
130
+
131
+ m.singular_int32 = -42
132
+ assert_equal -42, m.singular_int32
133
+ m.clear_singular_int32
134
+ assert_equal 0, m.singular_int32
135
+
136
+ m.singular_int32 = 50
137
+ assert_equal 50, m.singular_int32
138
+ TestSingularFields.descriptor.lookup('singular_int32').clear(m)
139
+ assert_equal 0, m.singular_int32
140
+
141
+ m.singular_string = "foo bar"
142
+ assert_equal "foo bar", m.singular_string
143
+ m.clear_singular_string
144
+ assert_equal "", m.singular_string
145
+
146
+ m.singular_string = "foo"
147
+ assert_equal "foo", m.singular_string
148
+ TestSingularFields.descriptor.lookup('singular_string').clear(m)
149
+ assert_equal "", m.singular_string
150
+
151
+ m.singular_msg = TestMessage2.new(:foo => 42)
152
+ assert_equal TestMessage2.new(:foo => 42), m.singular_msg
153
+ assert m.has_singular_msg?
154
+ m.clear_singular_msg
155
+ assert_equal nil, m.singular_msg
156
+ assert !m.has_singular_msg?
157
+
158
+ m.singular_msg = TestMessage2.new(:foo => 42)
159
+ assert_equal TestMessage2.new(:foo => 42), m.singular_msg
160
+ TestSingularFields.descriptor.lookup('singular_msg').clear(m)
161
+ assert_equal nil, m.singular_msg
162
+ end
84
163
 
85
- m.optional_int32 = -42
86
- assert_equal -42, m.optional_int32
87
- m.clear_optional_int32
88
- assert_equal 0, m.optional_int32
89
-
90
- m.optional_int32 = 50
91
- assert_equal 50, m.optional_int32
92
- TestMessage.descriptor.lookup('optional_int32').clear(m)
93
- assert_equal 0, m.optional_int32
94
-
95
- m.optional_string = "foo bar"
96
- assert_equal "foo bar", m.optional_string
97
- m.clear_optional_string
98
- assert_equal "", m.optional_string
99
-
100
- m.optional_string = "foo"
101
- assert_equal "foo", m.optional_string
102
- TestMessage.descriptor.lookup('optional_string').clear(m)
103
- assert_equal "", m.optional_string
104
-
105
- m.optional_msg = TestMessage2.new(:foo => 42)
106
- assert_equal TestMessage2.new(:foo => 42), m.optional_msg
107
- assert m.has_optional_msg?
108
- m.clear_optional_msg
109
- assert_equal nil, m.optional_msg
110
- assert !m.has_optional_msg?
111
-
112
- m.optional_msg = TestMessage2.new(:foo => 42)
113
- assert_equal TestMessage2.new(:foo => 42), m.optional_msg
114
- TestMessage.descriptor.lookup('optional_msg').clear(m)
115
- assert_equal nil, m.optional_msg
164
+ def test_clear_repeated_fields
165
+ m = TestMessage.new
116
166
 
117
167
  m.repeated_int32.push(1)
118
168
  assert_equal [1], m.repeated_int32
@@ -128,6 +178,7 @@ module BasicTest
128
178
  m.a = "foo"
129
179
  assert_equal "foo", m.a
130
180
  assert m.has_my_oneof?
181
+ assert_equal :a, m.my_oneof
131
182
  m.clear_a
132
183
  assert !m.has_my_oneof?
133
184
 
@@ -143,7 +194,6 @@ module BasicTest
143
194
  assert !m.has_my_oneof?
144
195
  end
145
196
 
146
-
147
197
  def test_initialization_map_errors
148
198
  e = assert_raise ArgumentError do
149
199
  TestMessage.new(:hello => "world")
@@ -198,7 +248,7 @@ module BasicTest
198
248
  m.map_string_int32 = {}
199
249
  end
200
250
 
201
- assert_raise TypeError do
251
+ assert_raise Google::Protobuf::TypeError do
202
252
  m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
203
253
  end
204
254
  end
@@ -223,8 +273,12 @@ module BasicTest
223
273
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
224
274
  "b" => TestMessage2.new(:foo => 2)},
225
275
  :map_string_enum => {"a" => :A, "b" => :B})
226
- expected = "<BasicTest::MapMessage: map_string_int32: {\"b\"=>2, \"a\"=>1}, map_string_msg: {\"b\"=><BasicTest::TestMessage2: foo: 2>, \"a\"=><BasicTest::TestMessage2: foo: 1>}, map_string_enum: {\"b\"=>:B, \"a\"=>:A}>"
227
- assert_equal expected, m.inspect
276
+
277
+ # JRuby doesn't keep consistent ordering so check for either version
278
+ expected_a = "<BasicTest::MapMessage: map_string_int32: {\"b\"=>2, \"a\"=>1}, map_string_msg: {\"b\"=><BasicTest::TestMessage2: foo: 2>, \"a\"=><BasicTest::TestMessage2: foo: 1>}, map_string_enum: {\"b\"=>:B, \"a\"=>:A}>"
279
+ expected_b = "<BasicTest::MapMessage: map_string_int32: {\"a\"=>1, \"b\"=>2}, map_string_msg: {\"a\"=><BasicTest::TestMessage2: foo: 1>, \"b\"=><BasicTest::TestMessage2: foo: 2>}, map_string_enum: {\"a\"=>:A, \"b\"=>:B}>"
280
+ inspect_result = m.inspect
281
+ assert expected_a == inspect_result || expected_b == inspect_result, "Incorrect inspect result: #{inspect_result}"
228
282
  end
229
283
 
230
284
  def test_map_corruption
@@ -276,6 +330,86 @@ module BasicTest
276
330
  assert_equal m5, m
277
331
  end
278
332
 
333
+ def test_map_wrappers_with_default_values
334
+ run_asserts = ->(m) {
335
+ assert_equal 0.0, m.map_double[0].value
336
+ assert_equal 0.0, m.map_float[0].value
337
+ assert_equal 0, m.map_int32[0].value
338
+ assert_equal 0, m.map_int64[0].value
339
+ assert_equal 0, m.map_uint32[0].value
340
+ assert_equal 0, m.map_uint64[0].value
341
+ assert_equal false, m.map_bool[0].value
342
+ assert_equal '', m.map_string[0].value
343
+ assert_equal '', m.map_bytes[0].value
344
+ }
345
+
346
+ m = proto_module::Wrapper.new(
347
+ map_double: {0 => Google::Protobuf::DoubleValue.new(value: 0.0)},
348
+ map_float: {0 => Google::Protobuf::FloatValue.new(value: 0.0)},
349
+ map_int32: {0 => Google::Protobuf::Int32Value.new(value: 0)},
350
+ map_int64: {0 => Google::Protobuf::Int64Value.new(value: 0)},
351
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 0)},
352
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 0)},
353
+ map_bool: {0 => Google::Protobuf::BoolValue.new(value: false)},
354
+ map_string: {0 => Google::Protobuf::StringValue.new(value: '')},
355
+ map_bytes: {0 => Google::Protobuf::BytesValue.new(value: '')},
356
+ )
357
+
358
+ run_asserts.call(m)
359
+ serialized = proto_module::Wrapper::encode(m)
360
+ m2 = proto_module::Wrapper::decode(serialized)
361
+ run_asserts.call(m2)
362
+
363
+ # Test the case where we are serializing directly from the parsed form
364
+ # (before anything lazy is materialized).
365
+ m3 = proto_module::Wrapper::decode(serialized)
366
+ serialized2 = proto_module::Wrapper::encode(m3)
367
+ m4 = proto_module::Wrapper::decode(serialized2)
368
+ run_asserts.call(m4)
369
+
370
+ # Test that the lazy form compares equal to the expanded form.
371
+ m5 = proto_module::Wrapper::decode(serialized2)
372
+ assert_equal m5, m
373
+ end
374
+
375
+ def test_map_wrappers_with_no_value
376
+ run_asserts = ->(m) {
377
+ assert_equal 0.0, m.map_double[0].value
378
+ assert_equal 0.0, m.map_float[0].value
379
+ assert_equal 0, m.map_int32[0].value
380
+ assert_equal 0, m.map_int64[0].value
381
+ assert_equal 0, m.map_uint32[0].value
382
+ assert_equal 0, m.map_uint64[0].value
383
+ assert_equal false, m.map_bool[0].value
384
+ assert_equal '', m.map_string[0].value
385
+ assert_equal '', m.map_bytes[0].value
386
+ }
387
+
388
+ m = proto_module::Wrapper.new(
389
+ map_double: {0 => Google::Protobuf::DoubleValue.new()},
390
+ map_float: {0 => Google::Protobuf::FloatValue.new()},
391
+ map_int32: {0 => Google::Protobuf::Int32Value.new()},
392
+ map_int64: {0 => Google::Protobuf::Int64Value.new()},
393
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new()},
394
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new()},
395
+ map_bool: {0 => Google::Protobuf::BoolValue.new()},
396
+ map_string: {0 => Google::Protobuf::StringValue.new()},
397
+ map_bytes: {0 => Google::Protobuf::BytesValue.new()},
398
+ )
399
+ run_asserts.call(m)
400
+
401
+ serialized = proto_module::Wrapper::encode(m)
402
+ m2 = proto_module::Wrapper::decode(serialized)
403
+ run_asserts.call(m2)
404
+
405
+ # Test the case where we are serializing directly from the parsed form
406
+ # (before anything lazy is materialized).
407
+ m3 = proto_module::Wrapper::decode(serialized)
408
+ serialized2 = proto_module::Wrapper::encode(m3)
409
+ m4 = proto_module::Wrapper::decode(serialized2)
410
+ run_asserts.call(m4)
411
+ end
412
+
279
413
  def test_concurrent_decoding
280
414
  o = Outer.new
281
415
  o.items[0] = Inner.new
@@ -345,6 +479,7 @@ module BasicTest
345
479
  :optional_int32=>0,
346
480
  :optional_int64=>0,
347
481
  :optional_msg=>nil,
482
+ :optional_msg2=>nil,
348
483
  :optional_string=>"foo",
349
484
  :optional_uint32=>0,
350
485
  :optional_uint64=>0,
@@ -382,9 +517,9 @@ module BasicTest
382
517
  m = MapMessage.new(:map_string_int32 => {"a" => 1})
383
518
  expected = {mapStringInt32: {a: 1}, mapStringMsg: {}, mapStringEnum: {}}
384
519
  expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}, map_string_enum: {}}
385
- assert_equal JSON.parse(MapMessage.encode_json(m), :symbolize_names => true), expected
520
+ assert_equal JSON.parse(MapMessage.encode_json(m, :emit_defaults=>true), :symbolize_names => true), expected
386
521
 
387
- json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true)
522
+ json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true, :emit_defaults=>true)
388
523
  assert_equal JSON.parse(json, :symbolize_names => true), expected_preserve
389
524
 
390
525
  m2 = MapMessage.decode_json(MapMessage.encode_json(m))
@@ -394,7 +529,7 @@ module BasicTest
394
529
  def test_json_maps_emit_defaults_submsg
395
530
  # TODO: Fix JSON in JRuby version.
396
531
  return if RUBY_PLATFORM == "java"
397
- m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new})
532
+ m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new(foo: 0)})
398
533
  expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}, mapStringEnum: {}}
399
534
 
400
535
  actual = MapMessage.encode_json(m, :emit_defaults => true)
@@ -402,6 +537,30 @@ module BasicTest
402
537
  assert_equal JSON.parse(actual, :symbolize_names => true), expected
403
538
  end
404
539
 
540
+ def test_json_emit_defaults_submsg
541
+ # TODO: Fix JSON in JRuby version.
542
+ return if RUBY_PLATFORM == "java"
543
+ m = TestSingularFields.new(singular_msg: proto_module::TestMessage2.new)
544
+
545
+ expected = {
546
+ singularInt32: 0,
547
+ singularInt64: "0",
548
+ singularUint32: 0,
549
+ singularUint64: "0",
550
+ singularBool: false,
551
+ singularFloat: 0,
552
+ singularDouble: 0,
553
+ singularString: "",
554
+ singularBytes: "",
555
+ singularMsg: {},
556
+ singularEnum: "Default",
557
+ }
558
+
559
+ actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
560
+
561
+ assert_equal expected, JSON.parse(actual, :symbolize_names => true)
562
+ end
563
+
405
564
  def test_respond_to
406
565
  # This test fails with JRuby 1.7.23, likely because of an old JRuby bug.
407
566
  return if RUBY_PLATFORM == "java"