google-protobuf 3.7.1 → 3.17.3

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.

Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/convert.c +349 -0
  3. data/ext/google/protobuf_c/convert.h +72 -0
  4. data/ext/google/protobuf_c/defs.c +1555 -1228
  5. data/ext/google/protobuf_c/defs.h +107 -0
  6. data/ext/google/protobuf_c/extconf.rb +5 -7
  7. data/ext/google/protobuf_c/map.c +312 -470
  8. data/ext/google/protobuf_c/map.h +67 -0
  9. data/ext/google/protobuf_c/message.c +942 -348
  10. data/ext/google/protobuf_c/message.h +101 -0
  11. data/ext/google/protobuf_c/protobuf.c +400 -51
  12. data/ext/google/protobuf_c/protobuf.h +47 -545
  13. data/ext/google/protobuf_c/repeated_field.c +313 -308
  14. data/ext/google/protobuf_c/repeated_field.h +63 -0
  15. data/ext/google/protobuf_c/ruby-upb.c +8858 -0
  16. data/ext/google/protobuf_c/ruby-upb.h +4411 -0
  17. data/ext/google/protobuf_c/third_party/wyhash/wyhash.h +145 -0
  18. data/lib/google/protobuf.rb +70 -0
  19. data/lib/google/protobuf/any_pb.rb +1 -1
  20. data/lib/google/protobuf/api_pb.rb +3 -3
  21. data/lib/google/protobuf/duration_pb.rb +1 -1
  22. data/lib/google/protobuf/empty_pb.rb +1 -1
  23. data/lib/google/protobuf/field_mask_pb.rb +1 -1
  24. data/lib/google/protobuf/source_context_pb.rb +1 -1
  25. data/lib/google/protobuf/struct_pb.rb +4 -4
  26. data/lib/google/protobuf/timestamp_pb.rb +1 -1
  27. data/lib/google/protobuf/type_pb.rb +8 -8
  28. data/lib/google/protobuf/well_known_types.rb +8 -2
  29. data/lib/google/protobuf/wrappers_pb.rb +9 -9
  30. data/tests/basic.rb +320 -70
  31. data/tests/generated_code_test.rb +0 -0
  32. data/tests/stress.rb +0 -0
  33. metadata +27 -15
  34. data/ext/google/protobuf_c/encode_decode.c +0 -1614
  35. data/ext/google/protobuf_c/storage.c +0 -1032
  36. data/ext/google/protobuf_c/upb.c +0 -17480
  37. data/ext/google/protobuf_c/upb.h +0 -10642
@@ -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
@@ -50,6 +50,76 @@ else
50
50
  rescue LoadError
51
51
  require 'google/protobuf_c'
52
52
  end
53
+
54
+ module Google
55
+ module Protobuf
56
+ module Internal
57
+ def self.infer_package(names)
58
+ # Package is longest common prefix ending in '.', if any.
59
+ if not names.empty?
60
+ min, max = names.minmax
61
+ last_common_dot = nil
62
+ min.size.times { |i|
63
+ if min[i] != max[i] then break end
64
+ if min[i] == ?. then last_common_dot = i end
65
+ }
66
+ if last_common_dot
67
+ return min.slice(0, last_common_dot)
68
+ end
69
+ end
70
+
71
+ nil
72
+ end
73
+
74
+ class NestingBuilder
75
+ def initialize(msg_names, enum_names)
76
+ @to_pos = {nil=>nil}
77
+ @msg_children = Hash.new { |hash, key| hash[key] = [] }
78
+ @enum_children = Hash.new { |hash, key| hash[key] = [] }
79
+
80
+ msg_names.each_with_index { |name, idx| @to_pos[name] = idx }
81
+ enum_names.each_with_index { |name, idx| @to_pos[name] = idx }
82
+
83
+ msg_names.each { |name| @msg_children[parent(name)] << name }
84
+ enum_names.each { |name| @enum_children[parent(name)] << name }
85
+ end
86
+
87
+ def build(package)
88
+ return build_msg(package)
89
+ end
90
+
91
+ private
92
+ def build_msg(msg)
93
+ return {
94
+ :pos => @to_pos[msg],
95
+ :msgs => @msg_children[msg].map { |child| build_msg(child) },
96
+ :enums => @enum_children[msg].map { |child| @to_pos[child] },
97
+ }
98
+ end
99
+
100
+ private
101
+ def parent(name)
102
+ idx = name.rindex(?.)
103
+ if idx
104
+ return name.slice(0, idx)
105
+ else
106
+ return nil
107
+ end
108
+ end
109
+ end
110
+
111
+ def self.fixup_descriptor(package, msg_names, enum_names)
112
+ if package.nil?
113
+ package = self.infer_package(msg_names + enum_names)
114
+ end
115
+
116
+ nesting = NestingBuilder.new(msg_names, enum_names).build(package)
117
+
118
+ return package, nesting
119
+ end
120
+ end
121
+ end
122
+ end
53
123
  end
54
124
 
55
125
  require 'google/protobuf/repeated_field'
@@ -14,6 +14,6 @@ end
14
14
 
15
15
  module Google
16
16
  module Protobuf
17
- Any = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Any").msgclass
17
+ Any = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Any").msgclass
18
18
  end
19
19
  end
@@ -34,8 +34,8 @@ end
34
34
 
35
35
  module Google
36
36
  module Protobuf
37
- Api = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Api").msgclass
38
- Method = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Method").msgclass
39
- Mixin = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Mixin").msgclass
37
+ Api = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Api").msgclass
38
+ Method = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Method").msgclass
39
+ Mixin = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Mixin").msgclass
40
40
  end
41
41
  end
@@ -14,6 +14,6 @@ end
14
14
 
15
15
  module Google
16
16
  module Protobuf
17
- Duration = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Duration").msgclass
17
+ Duration = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Duration").msgclass
18
18
  end
19
19
  end
@@ -12,6 +12,6 @@ end
12
12
 
13
13
  module Google
14
14
  module Protobuf
15
- Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Empty").msgclass
15
+ Empty = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Empty").msgclass
16
16
  end
17
17
  end
@@ -13,6 +13,6 @@ end
13
13
 
14
14
  module Google
15
15
  module Protobuf
16
- FieldMask = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldMask").msgclass
16
+ FieldMask = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FieldMask").msgclass
17
17
  end
18
18
  end
@@ -13,6 +13,6 @@ end
13
13
 
14
14
  module Google
15
15
  module Protobuf
16
- SourceContext = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.SourceContext").msgclass
16
+ SourceContext = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.SourceContext").msgclass
17
17
  end
18
18
  end
@@ -29,9 +29,9 @@ end
29
29
 
30
30
  module Google
31
31
  module Protobuf
32
- Struct = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Struct").msgclass
33
- Value = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Value").msgclass
34
- ListValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ListValue").msgclass
35
- NullValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.NullValue").enummodule
32
+ Struct = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Struct").msgclass
33
+ Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Value").msgclass
34
+ ListValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.ListValue").msgclass
35
+ NullValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.NullValue").enummodule
36
36
  end
37
37
  end
@@ -14,6 +14,6 @@ end
14
14
 
15
15
  module Google
16
16
  module Protobuf
17
- Timestamp = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Timestamp").msgclass
17
+ Timestamp = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Timestamp").msgclass
18
18
  end
19
19
  end
@@ -79,13 +79,13 @@ end
79
79
 
80
80
  module Google
81
81
  module Protobuf
82
- Type = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Type").msgclass
83
- Field = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field").msgclass
84
- Field::Kind = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field.Kind").enummodule
85
- Field::Cardinality = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field.Cardinality").enummodule
86
- Enum = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Enum").msgclass
87
- EnumValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumValue").msgclass
88
- Option = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Option").msgclass
89
- Syntax = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Syntax").enummodule
82
+ Type = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Type").msgclass
83
+ Field = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field").msgclass
84
+ Field::Kind = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field.Kind").enummodule
85
+ Field::Cardinality = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Field.Cardinality").enummodule
86
+ Enum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Enum").msgclass
87
+ EnumValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.EnumValue").msgclass
88
+ Option = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Option").msgclass
89
+ Syntax = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Syntax").enummodule
90
90
  end
91
91
  end
@@ -72,8 +72,14 @@ module Google
72
72
  end
73
73
 
74
74
  Timestamp.class_eval do
75
- def to_time
76
- Time.at(self.to_f)
75
+ if RUBY_VERSION < "2.5"
76
+ def to_time
77
+ Time.at(self.to_f)
78
+ end
79
+ else
80
+ def to_time
81
+ Time.at(seconds, nanos, :nanosecond)
82
+ end
77
83
  end
78
84
 
79
85
  def from_time(time)
@@ -37,14 +37,14 @@ end
37
37
 
38
38
  module Google
39
39
  module Protobuf
40
- DoubleValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DoubleValue").msgclass
41
- FloatValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FloatValue").msgclass
42
- Int64Value = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Int64Value").msgclass
43
- UInt64Value = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UInt64Value").msgclass
44
- Int32Value = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Int32Value").msgclass
45
- UInt32Value = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UInt32Value").msgclass
46
- BoolValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.BoolValue").msgclass
47
- StringValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.StringValue").msgclass
48
- BytesValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.BytesValue").msgclass
40
+ DoubleValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.DoubleValue").msgclass
41
+ FloatValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.FloatValue").msgclass
42
+ Int64Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Int64Value").msgclass
43
+ UInt64Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UInt64Value").msgclass
44
+ Int32Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Int32Value").msgclass
45
+ UInt32Value = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.UInt32Value").msgclass
46
+ BoolValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.BoolValue").msgclass
47
+ StringValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.StringValue").msgclass
48
+ BytesValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.BytesValue").msgclass
49
49
  end
50
50
  end
data/tests/basic.rb CHANGED
@@ -17,7 +17,6 @@ module BasicTest
17
17
  add_message "BadFieldNames" do
18
18
  optional :dup, :int32, 1
19
19
  optional :class, :int32, 2
20
- optional :"a.b", :int32, 3
21
20
  end
22
21
  end
23
22
 
@@ -32,12 +31,51 @@ module BasicTest
32
31
  end
33
32
  include CommonTests
34
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
+
66
+ def test_issue_8559_crash
67
+ msg = TestMessage.new
68
+ msg.repeated_int32 = ::Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
69
+ GC.start(full_mark: true, immediate_sweep: true)
70
+ TestMessage.encode(msg)
71
+ end
72
+
35
73
  def test_has_field
36
- m = TestMessage.new
37
- assert !m.has_optional_msg?
38
- m.optional_msg = TestMessage2.new
39
- assert m.has_optional_msg?
40
- assert TestMessage.descriptor.lookup('optional_msg').has?(m)
74
+ m = TestSingularFields.new
75
+ assert !m.has_singular_msg?
76
+ m.singular_msg = TestMessage2.new
77
+ assert m.has_singular_msg?
78
+ assert TestSingularFields.descriptor.lookup('singular_msg').has?(m)
41
79
 
42
80
  m = OneofMessage.new
43
81
  assert !m.has_my_oneof?
@@ -46,32 +84,31 @@ module BasicTest
46
84
  assert_raise NoMethodError do
47
85
  m.has_a?
48
86
  end
49
- assert_raise ArgumentError do
50
- OneofMessage.descriptor.lookup('a').has?(m)
51
- end
87
+ assert_true OneofMessage.descriptor.lookup('a').has?(m)
52
88
 
53
- m = TestMessage.new
89
+ m = TestSingularFields.new
54
90
  assert_raise NoMethodError do
55
- m.has_optional_int32?
91
+ m.has_singular_int32?
56
92
  end
57
93
  assert_raise ArgumentError do
58
- TestMessage.descriptor.lookup('optional_int32').has?(m)
94
+ TestSingularFields.descriptor.lookup('singular_int32').has?(m)
59
95
  end
60
96
 
61
97
  assert_raise NoMethodError do
62
- m.has_optional_string?
98
+ m.has_singular_string?
63
99
  end
64
100
  assert_raise ArgumentError do
65
- TestMessage.descriptor.lookup('optional_string').has?(m)
101
+ TestSingularFields.descriptor.lookup('singular_string').has?(m)
66
102
  end
67
103
 
68
104
  assert_raise NoMethodError do
69
- m.has_optional_bool?
105
+ m.has_singular_bool?
70
106
  end
71
107
  assert_raise ArgumentError do
72
- TestMessage.descriptor.lookup('optional_bool').has?(m)
108
+ TestSingularFields.descriptor.lookup('singular_bool').has?(m)
73
109
  end
74
110
 
111
+ m = TestMessage.new
75
112
  assert_raise NoMethodError do
76
113
  m.has_repeated_msg?
77
114
  end
@@ -80,40 +117,59 @@ module BasicTest
80
117
  end
81
118
  end
82
119
 
120
+ def test_no_presence
121
+ m = TestSingularFields.new
122
+
123
+ # Explicitly setting to zero does not cause anything to be serialized.
124
+ m.singular_int32 = 0
125
+ assert_equal "", TestSingularFields.encode(m)
126
+
127
+ # Explicitly setting to a non-zero value *does* cause serialization.
128
+ m.singular_int32 = 1
129
+ assert_not_equal "", TestSingularFields.encode(m)
130
+
131
+ m.singular_int32 = 0
132
+ assert_equal "", TestSingularFields.encode(m)
133
+ end
134
+
83
135
  def test_set_clear_defaults
84
- m = TestMessage.new
136
+ m = TestSingularFields.new
137
+
138
+ m.singular_int32 = -42
139
+ assert_equal -42, m.singular_int32
140
+ m.clear_singular_int32
141
+ assert_equal 0, m.singular_int32
142
+
143
+ m.singular_int32 = 50
144
+ assert_equal 50, m.singular_int32
145
+ TestSingularFields.descriptor.lookup('singular_int32').clear(m)
146
+ assert_equal 0, m.singular_int32
147
+
148
+ m.singular_string = "foo bar"
149
+ assert_equal "foo bar", m.singular_string
150
+ m.clear_singular_string
151
+ assert_equal "", m.singular_string
152
+
153
+ m.singular_string = "foo"
154
+ assert_equal "foo", m.singular_string
155
+ TestSingularFields.descriptor.lookup('singular_string').clear(m)
156
+ assert_equal "", m.singular_string
157
+
158
+ m.singular_msg = TestMessage2.new(:foo => 42)
159
+ assert_equal TestMessage2.new(:foo => 42), m.singular_msg
160
+ assert m.has_singular_msg?
161
+ m.clear_singular_msg
162
+ assert_equal nil, m.singular_msg
163
+ assert !m.has_singular_msg?
164
+
165
+ m.singular_msg = TestMessage2.new(:foo => 42)
166
+ assert_equal TestMessage2.new(:foo => 42), m.singular_msg
167
+ TestSingularFields.descriptor.lookup('singular_msg').clear(m)
168
+ assert_equal nil, m.singular_msg
169
+ end
85
170
 
86
- m.optional_int32 = -42
87
- assert_equal -42, m.optional_int32
88
- m.clear_optional_int32
89
- assert_equal 0, m.optional_int32
90
-
91
- m.optional_int32 = 50
92
- assert_equal 50, m.optional_int32
93
- TestMessage.descriptor.lookup('optional_int32').clear(m)
94
- assert_equal 0, m.optional_int32
95
-
96
- m.optional_string = "foo bar"
97
- assert_equal "foo bar", m.optional_string
98
- m.clear_optional_string
99
- assert_equal "", m.optional_string
100
-
101
- m.optional_string = "foo"
102
- assert_equal "foo", m.optional_string
103
- TestMessage.descriptor.lookup('optional_string').clear(m)
104
- assert_equal "", m.optional_string
105
-
106
- m.optional_msg = TestMessage2.new(:foo => 42)
107
- assert_equal TestMessage2.new(:foo => 42), m.optional_msg
108
- assert m.has_optional_msg?
109
- m.clear_optional_msg
110
- assert_equal nil, m.optional_msg
111
- assert !m.has_optional_msg?
112
-
113
- m.optional_msg = TestMessage2.new(:foo => 42)
114
- assert_equal TestMessage2.new(:foo => 42), m.optional_msg
115
- TestMessage.descriptor.lookup('optional_msg').clear(m)
116
- assert_equal nil, m.optional_msg
171
+ def test_clear_repeated_fields
172
+ m = TestMessage.new
117
173
 
118
174
  m.repeated_int32.push(1)
119
175
  assert_equal [1], m.repeated_int32
@@ -129,6 +185,7 @@ module BasicTest
129
185
  m.a = "foo"
130
186
  assert_equal "foo", m.a
131
187
  assert m.has_my_oneof?
188
+ assert_equal :a, m.my_oneof
132
189
  m.clear_a
133
190
  assert !m.has_my_oneof?
134
191
 
@@ -144,7 +201,6 @@ module BasicTest
144
201
  assert !m.has_my_oneof?
145
202
  end
146
203
 
147
-
148
204
  def test_initialization_map_errors
149
205
  e = assert_raise ArgumentError do
150
206
  TestMessage.new(:hello => "world")
@@ -170,10 +226,12 @@ module BasicTest
170
226
  m = MapMessage.new(
171
227
  :map_string_int32 => {"a" => 1, "b" => 2},
172
228
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
173
- "b" => TestMessage2.new(:foo => 2)})
229
+ "b" => TestMessage2.new(:foo => 2)},
230
+ :map_string_enum => {"a" => :A, "b" => :B})
174
231
  assert m.map_string_int32.keys.sort == ["a", "b"]
175
232
  assert m.map_string_int32["a"] == 1
176
233
  assert m.map_string_msg["b"].foo == 2
234
+ assert m.map_string_enum["a"] == :A
177
235
 
178
236
  m.map_string_int32["c"] = 3
179
237
  assert m.map_string_int32["c"] == 3
@@ -197,18 +255,37 @@ module BasicTest
197
255
  m.map_string_int32 = {}
198
256
  end
199
257
 
200
- assert_raise TypeError do
258
+ assert_raise Google::Protobuf::TypeError do
201
259
  m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
202
260
  end
203
261
  end
204
262
 
263
+ def test_map_field_with_symbol
264
+ m = MapMessage.new
265
+ assert m.map_string_int32 == {}
266
+ assert m.map_string_msg == {}
267
+
268
+ m = MapMessage.new(
269
+ :map_string_int32 => {a: 1, "b" => 2},
270
+ :map_string_msg => {a: TestMessage2.new(:foo => 1),
271
+ b: TestMessage2.new(:foo => 10)})
272
+ assert_equal 1, m.map_string_int32[:a]
273
+ assert_equal 2, m.map_string_int32[:b]
274
+ assert_equal 10, m.map_string_msg[:b].foo
275
+ end
276
+
205
277
  def test_map_inspect
206
278
  m = MapMessage.new(
207
279
  :map_string_int32 => {"a" => 1, "b" => 2},
208
280
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
209
- "b" => TestMessage2.new(:foo => 2)})
210
- expected = "<BasicTest::MapMessage: map_string_int32: {\"b\"=>2, \"a\"=>1}, map_string_msg: {\"b\"=><BasicTest::TestMessage2: foo: 2>, \"a\"=><BasicTest::TestMessage2: foo: 1>}>"
211
- assert_equal expected, m.inspect
281
+ "b" => TestMessage2.new(:foo => 2)},
282
+ :map_string_enum => {"a" => :A, "b" => :B})
283
+
284
+ # JRuby doesn't keep consistent ordering so check for either version
285
+ 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}>"
286
+ 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}>"
287
+ inspect_result = m.inspect
288
+ assert expected_a == inspect_result || expected_b == inspect_result, "Incorrect inspect result: #{inspect_result}"
212
289
  end
213
290
 
214
291
  def test_map_corruption
@@ -218,6 +295,128 @@ module BasicTest
218
295
  m.map_string_int32['aaa'] = 3
219
296
  end
220
297
 
298
+ def test_map_wrappers
299
+ run_asserts = ->(m) {
300
+ assert_equal 2.0, m.map_double[0].value
301
+ assert_equal 4.0, m.map_float[0].value
302
+ assert_equal 3, m.map_int32[0].value
303
+ assert_equal 4, m.map_int64[0].value
304
+ assert_equal 5, m.map_uint32[0].value
305
+ assert_equal 6, m.map_uint64[0].value
306
+ assert_equal true, m.map_bool[0].value
307
+ assert_equal 'str', m.map_string[0].value
308
+ assert_equal 'fun', m.map_bytes[0].value
309
+ }
310
+
311
+ m = proto_module::Wrapper.new(
312
+ map_double: {0 => Google::Protobuf::DoubleValue.new(value: 2.0)},
313
+ map_float: {0 => Google::Protobuf::FloatValue.new(value: 4.0)},
314
+ map_int32: {0 => Google::Protobuf::Int32Value.new(value: 3)},
315
+ map_int64: {0 => Google::Protobuf::Int64Value.new(value: 4)},
316
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 5)},
317
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 6)},
318
+ map_bool: {0 => Google::Protobuf::BoolValue.new(value: true)},
319
+ map_string: {0 => Google::Protobuf::StringValue.new(value: 'str')},
320
+ map_bytes: {0 => Google::Protobuf::BytesValue.new(value: 'fun')},
321
+ )
322
+
323
+ run_asserts.call(m)
324
+ serialized = proto_module::Wrapper::encode(m)
325
+ m2 = proto_module::Wrapper::decode(serialized)
326
+ run_asserts.call(m2)
327
+
328
+ # Test the case where we are serializing directly from the parsed form
329
+ # (before anything lazy is materialized).
330
+ m3 = proto_module::Wrapper::decode(serialized)
331
+ serialized2 = proto_module::Wrapper::encode(m3)
332
+ m4 = proto_module::Wrapper::decode(serialized2)
333
+ run_asserts.call(m4)
334
+
335
+ # Test that the lazy form compares equal to the expanded form.
336
+ m5 = proto_module::Wrapper::decode(serialized2)
337
+ assert_equal m5, m
338
+ end
339
+
340
+ def test_map_wrappers_with_default_values
341
+ run_asserts = ->(m) {
342
+ assert_equal 0.0, m.map_double[0].value
343
+ assert_equal 0.0, m.map_float[0].value
344
+ assert_equal 0, m.map_int32[0].value
345
+ assert_equal 0, m.map_int64[0].value
346
+ assert_equal 0, m.map_uint32[0].value
347
+ assert_equal 0, m.map_uint64[0].value
348
+ assert_equal false, m.map_bool[0].value
349
+ assert_equal '', m.map_string[0].value
350
+ assert_equal '', m.map_bytes[0].value
351
+ }
352
+
353
+ m = proto_module::Wrapper.new(
354
+ map_double: {0 => Google::Protobuf::DoubleValue.new(value: 0.0)},
355
+ map_float: {0 => Google::Protobuf::FloatValue.new(value: 0.0)},
356
+ map_int32: {0 => Google::Protobuf::Int32Value.new(value: 0)},
357
+ map_int64: {0 => Google::Protobuf::Int64Value.new(value: 0)},
358
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 0)},
359
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 0)},
360
+ map_bool: {0 => Google::Protobuf::BoolValue.new(value: false)},
361
+ map_string: {0 => Google::Protobuf::StringValue.new(value: '')},
362
+ map_bytes: {0 => Google::Protobuf::BytesValue.new(value: '')},
363
+ )
364
+
365
+ run_asserts.call(m)
366
+ serialized = proto_module::Wrapper::encode(m)
367
+ m2 = proto_module::Wrapper::decode(serialized)
368
+ run_asserts.call(m2)
369
+
370
+ # Test the case where we are serializing directly from the parsed form
371
+ # (before anything lazy is materialized).
372
+ m3 = proto_module::Wrapper::decode(serialized)
373
+ serialized2 = proto_module::Wrapper::encode(m3)
374
+ m4 = proto_module::Wrapper::decode(serialized2)
375
+ run_asserts.call(m4)
376
+
377
+ # Test that the lazy form compares equal to the expanded form.
378
+ m5 = proto_module::Wrapper::decode(serialized2)
379
+ assert_equal m5, m
380
+ end
381
+
382
+ def test_map_wrappers_with_no_value
383
+ run_asserts = ->(m) {
384
+ assert_equal 0.0, m.map_double[0].value
385
+ assert_equal 0.0, m.map_float[0].value
386
+ assert_equal 0, m.map_int32[0].value
387
+ assert_equal 0, m.map_int64[0].value
388
+ assert_equal 0, m.map_uint32[0].value
389
+ assert_equal 0, m.map_uint64[0].value
390
+ assert_equal false, m.map_bool[0].value
391
+ assert_equal '', m.map_string[0].value
392
+ assert_equal '', m.map_bytes[0].value
393
+ }
394
+
395
+ m = proto_module::Wrapper.new(
396
+ map_double: {0 => Google::Protobuf::DoubleValue.new()},
397
+ map_float: {0 => Google::Protobuf::FloatValue.new()},
398
+ map_int32: {0 => Google::Protobuf::Int32Value.new()},
399
+ map_int64: {0 => Google::Protobuf::Int64Value.new()},
400
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new()},
401
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new()},
402
+ map_bool: {0 => Google::Protobuf::BoolValue.new()},
403
+ map_string: {0 => Google::Protobuf::StringValue.new()},
404
+ map_bytes: {0 => Google::Protobuf::BytesValue.new()},
405
+ )
406
+ run_asserts.call(m)
407
+
408
+ serialized = proto_module::Wrapper::encode(m)
409
+ m2 = proto_module::Wrapper::decode(serialized)
410
+ run_asserts.call(m2)
411
+
412
+ # Test the case where we are serializing directly from the parsed form
413
+ # (before anything lazy is materialized).
414
+ m3 = proto_module::Wrapper::decode(serialized)
415
+ serialized2 = proto_module::Wrapper::encode(m3)
416
+ m4 = proto_module::Wrapper::decode(serialized2)
417
+ run_asserts.call(m4)
418
+ end
419
+
221
420
  def test_concurrent_decoding
222
421
  o = Outer.new
223
422
  o.items[0] = Inner.new
@@ -237,7 +436,8 @@ module BasicTest
237
436
  m = MapMessage.new(
238
437
  :map_string_int32 => {"a" => 1, "b" => 2},
239
438
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
240
- "b" => TestMessage2.new(:foo => 2)})
439
+ "b" => TestMessage2.new(:foo => 2)},
440
+ :map_string_enum => {"a" => :A, "b" => :B})
241
441
  m2 = MapMessage.decode(MapMessage.encode(m))
242
442
  assert m == m2
243
443
 
@@ -267,6 +467,14 @@ module BasicTest
267
467
  assert_match(/No such field: not_in_message/, e.message)
268
468
  end
269
469
 
470
+ #def test_json_quoted_string
471
+ # m = TestMessage.decode_json(%q(
472
+ # "optionalInt64": "1",,
473
+ # }))
474
+ # puts(m)
475
+ # assert_equal 1, m.optional_int32
476
+ #end
477
+
270
478
  def test_to_h
271
479
  m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'], :repeated_msg => [TestMessage2.new(:foo => 100)])
272
480
  expected_result = {
@@ -278,6 +486,7 @@ module BasicTest
278
486
  :optional_int32=>0,
279
487
  :optional_int64=>0,
280
488
  :optional_msg=>nil,
489
+ :optional_msg2=>nil,
281
490
  :optional_string=>"foo",
282
491
  :optional_uint32=>0,
283
492
  :optional_uint64=>0,
@@ -298,10 +507,12 @@ module BasicTest
298
507
  m = MapMessage.new(
299
508
  :map_string_int32 => {"a" => 1, "b" => 2},
300
509
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
301
- "b" => TestMessage2.new(:foo => 2)})
510
+ "b" => TestMessage2.new(:foo => 2)},
511
+ :map_string_enum => {"a" => :A, "b" => :B})
302
512
  expected_result = {
303
513
  :map_string_int32 => {"a" => 1, "b" => 2},
304
- :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}}
514
+ :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}},
515
+ :map_string_enum => {"a" => :A, "b" => :B}
305
516
  }
306
517
  assert_equal expected_result, m.to_h
307
518
  end
@@ -311,26 +522,50 @@ module BasicTest
311
522
  # TODO: Fix JSON in JRuby version.
312
523
  return if RUBY_PLATFORM == "java"
313
524
  m = MapMessage.new(:map_string_int32 => {"a" => 1})
314
- expected = {mapStringInt32: {a: 1}, mapStringMsg: {}}
315
- expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}}
316
- assert JSON.parse(MapMessage.encode_json(m), :symbolize_names => true) == expected
525
+ expected = {mapStringInt32: {a: 1}, mapStringMsg: {}, mapStringEnum: {}}
526
+ expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}, map_string_enum: {}}
527
+ assert_equal JSON.parse(MapMessage.encode_json(m, :emit_defaults=>true), :symbolize_names => true), expected
317
528
 
318
- json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true)
319
- assert JSON.parse(json, :symbolize_names => true) == expected_preserve
529
+ json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true, :emit_defaults=>true)
530
+ assert_equal JSON.parse(json, :symbolize_names => true), expected_preserve
320
531
 
321
532
  m2 = MapMessage.decode_json(MapMessage.encode_json(m))
322
- assert m == m2
533
+ assert_equal m, m2
323
534
  end
324
535
 
325
536
  def test_json_maps_emit_defaults_submsg
326
537
  # TODO: Fix JSON in JRuby version.
327
538
  return if RUBY_PLATFORM == "java"
328
- m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new})
329
- expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}}
539
+ m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new(foo: 0)})
540
+ expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}, mapStringEnum: {}}
330
541
 
331
542
  actual = MapMessage.encode_json(m, :emit_defaults => true)
332
543
 
333
- assert JSON.parse(actual, :symbolize_names => true) == expected
544
+ assert_equal JSON.parse(actual, :symbolize_names => true), expected
545
+ end
546
+
547
+ def test_json_emit_defaults_submsg
548
+ # TODO: Fix JSON in JRuby version.
549
+ return if RUBY_PLATFORM == "java"
550
+ m = TestSingularFields.new(singular_msg: proto_module::TestMessage2.new)
551
+
552
+ expected = {
553
+ singularInt32: 0,
554
+ singularInt64: "0",
555
+ singularUint32: 0,
556
+ singularUint64: "0",
557
+ singularBool: false,
558
+ singularFloat: 0,
559
+ singularDouble: 0,
560
+ singularString: "",
561
+ singularBytes: "",
562
+ singularMsg: {},
563
+ singularEnum: "Default",
564
+ }
565
+
566
+ actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
567
+
568
+ assert_equal expected, JSON.parse(actual, :symbolize_names => true)
334
569
  end
335
570
 
336
571
  def test_respond_to
@@ -351,11 +586,26 @@ module BasicTest
351
586
  assert nil != file_descriptor
352
587
  assert_equal "tests/basic_test.proto", file_descriptor.name
353
588
  assert_equal :proto3, file_descriptor.syntax
589
+ end
354
590
 
355
- file_descriptor = BadFieldNames.descriptor.file_descriptor
356
- assert nil != file_descriptor
357
- assert_equal nil, file_descriptor.name
358
- assert_equal :proto3, file_descriptor.syntax
591
+ # Ruby 2.5 changed to raise FrozenError instead of RuntimeError
592
+ FrozenErrorType = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5') ? RuntimeError : FrozenError
593
+
594
+ def test_map_freeze
595
+ m = proto_module::MapMessage.new
596
+ m.map_string_int32['a'] = 5
597
+ m.map_string_msg['b'] = proto_module::TestMessage2.new
598
+
599
+ m.map_string_int32.freeze
600
+ m.map_string_msg.freeze
601
+
602
+ assert m.map_string_int32.frozen?
603
+ assert m.map_string_msg.frozen?
604
+
605
+ assert_raise(FrozenErrorType) { m.map_string_int32['foo'] = 1 }
606
+ assert_raise(FrozenErrorType) { m.map_string_msg['bar'] = proto_module::TestMessage2.new }
607
+ assert_raise(FrozenErrorType) { m.map_string_int32.delete('a') }
608
+ assert_raise(FrozenErrorType) { m.map_string_int32.clear }
359
609
  end
360
610
  end
361
611
  end