basic.rb 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. #!/usr/bin/ruby
  2. # basic_test_pb.rb is in the same directory as this test.
  3. $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
  4. require 'basic_test_pb'
  5. require 'common_tests'
  6. require 'google/protobuf'
  7. require 'json'
  8. require 'test/unit'
  9. # ------------- generated code --------------
  10. module BasicTest
  11. pool = Google::Protobuf::DescriptorPool.new
  12. pool.build do
  13. add_message "BadFieldNames" do
  14. optional :dup, :int32, 1
  15. optional :class, :int32, 2
  16. end
  17. end
  18. BadFieldNames = pool.lookup("BadFieldNames").msgclass
  19. # ------------ test cases ---------------
  20. class MessageContainerTest < Test::Unit::TestCase
  21. # Required by CommonTests module to resolve proto3 proto classes used in tests.
  22. def proto_module
  23. ::BasicTest
  24. end
  25. include CommonTests
  26. def test_issue_8311_crash
  27. Google::Protobuf::DescriptorPool.generated_pool.build do
  28. add_file("inner.proto", :syntax => :proto3) do
  29. add_message "Inner" do
  30. # Removing either of these fixes the segfault.
  31. optional :foo, :string, 1
  32. optional :bar, :string, 2
  33. end
  34. end
  35. end
  36. Google::Protobuf::DescriptorPool.generated_pool.build do
  37. add_file("outer.proto", :syntax => :proto3) do
  38. add_message "Outer" do
  39. repeated :inners, :message, 1, "Inner"
  40. end
  41. end
  42. end
  43. outer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Outer").msgclass
  44. outer.new(
  45. inners: []
  46. )['inners'].to_s
  47. assert_raise Google::Protobuf::TypeError do
  48. outer.new(
  49. inners: [nil]
  50. ).to_s
  51. end
  52. end
  53. def test_issue_8559_crash
  54. msg = TestMessage.new
  55. msg.repeated_int32 = ::Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
  56. # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0
  57. if cruby_or_jruby_9_3_or_higher?
  58. GC.start(full_mark: true, immediate_sweep: true)
  59. end
  60. TestMessage.encode(msg)
  61. end
  62. def test_issue_9440
  63. msg = HelloRequest.new
  64. msg.id = 8
  65. assert_equal 8, msg.id
  66. msg.version = '1'
  67. assert_equal 8, msg.id
  68. end
  69. def test_issue_9507
  70. pool = Google::Protobuf::DescriptorPool.new
  71. pool.build do
  72. add_message "NpeMessage" do
  73. optional :type, :enum, 1, "TestEnum"
  74. optional :other, :string, 2
  75. end
  76. add_enum "TestEnum" do
  77. value :Something, 0
  78. end
  79. end
  80. msgclass = pool.lookup("NpeMessage").msgclass
  81. m = msgclass.new(
  82. other: "foo" # must be set, but can be blank
  83. )
  84. begin
  85. encoded = msgclass.encode(m)
  86. rescue java.lang.NullPointerException
  87. flunk "NPE rescued"
  88. end
  89. decoded = msgclass.decode(encoded)
  90. decoded.inspect
  91. decoded.to_proto
  92. end
  93. def test_has_field
  94. m = TestSingularFields.new
  95. assert !m.has_singular_msg?
  96. m.singular_msg = TestMessage2.new
  97. assert m.has_singular_msg?
  98. assert TestSingularFields.descriptor.lookup('singular_msg').has?(m)
  99. m = OneofMessage.new
  100. assert !m.has_my_oneof?
  101. m.a = "foo"
  102. assert m.has_my_oneof?
  103. assert_raise NoMethodError do
  104. m.has_a?
  105. end
  106. assert_true OneofMessage.descriptor.lookup('a').has?(m)
  107. m = TestSingularFields.new
  108. assert_raise NoMethodError do
  109. m.has_singular_int32?
  110. end
  111. assert_raise ArgumentError do
  112. TestSingularFields.descriptor.lookup('singular_int32').has?(m)
  113. end
  114. assert_raise NoMethodError do
  115. m.has_singular_string?
  116. end
  117. assert_raise ArgumentError do
  118. TestSingularFields.descriptor.lookup('singular_string').has?(m)
  119. end
  120. assert_raise NoMethodError do
  121. m.has_singular_bool?
  122. end
  123. assert_raise ArgumentError do
  124. TestSingularFields.descriptor.lookup('singular_bool').has?(m)
  125. end
  126. m = TestMessage.new
  127. assert_raise NoMethodError do
  128. m.has_repeated_msg?
  129. end
  130. assert_raise ArgumentError do
  131. TestMessage.descriptor.lookup('repeated_msg').has?(m)
  132. end
  133. end
  134. def test_no_presence
  135. m = TestSingularFields.new
  136. # Explicitly setting to zero does not cause anything to be serialized.
  137. m.singular_int32 = 0
  138. assert_equal "", TestSingularFields.encode(m)
  139. # Explicitly setting to a non-zero value *does* cause serialization.
  140. m.singular_int32 = 1
  141. assert_not_equal "", TestSingularFields.encode(m)
  142. m.singular_int32 = 0
  143. assert_equal "", TestSingularFields.encode(m)
  144. end
  145. def test_set_clear_defaults
  146. m = TestSingularFields.new
  147. m.singular_int32 = -42
  148. assert_equal( -42, m.singular_int32 )
  149. m.clear_singular_int32
  150. assert_equal 0, m.singular_int32
  151. m.singular_int32 = 50
  152. assert_equal 50, m.singular_int32
  153. TestSingularFields.descriptor.lookup('singular_int32').clear(m)
  154. assert_equal 0, m.singular_int32
  155. m.singular_string = "foo bar"
  156. assert_equal "foo bar", m.singular_string
  157. m.clear_singular_string
  158. assert_equal "", m.singular_string
  159. m.singular_string = "foo"
  160. assert_equal "foo", m.singular_string
  161. TestSingularFields.descriptor.lookup('singular_string').clear(m)
  162. assert_equal "", m.singular_string
  163. m.singular_msg = TestMessage2.new(:foo => 42)
  164. assert_equal TestMessage2.new(:foo => 42), m.singular_msg
  165. assert m.has_singular_msg?
  166. m.clear_singular_msg
  167. assert_equal nil, m.singular_msg
  168. assert !m.has_singular_msg?
  169. m.singular_msg = TestMessage2.new(:foo => 42)
  170. assert_equal TestMessage2.new(:foo => 42), m.singular_msg
  171. TestSingularFields.descriptor.lookup('singular_msg').clear(m)
  172. assert_equal nil, m.singular_msg
  173. end
  174. def test_import_proto2
  175. m = TestMessage.new
  176. assert !m.has_optional_proto2_submessage?
  177. m.optional_proto2_submessage = ::FooBar::Proto2::TestImportedMessage.new
  178. assert m.has_optional_proto2_submessage?
  179. assert TestMessage.descriptor.lookup('optional_proto2_submessage').has?(m)
  180. m.clear_optional_proto2_submessage
  181. assert !m.has_optional_proto2_submessage?
  182. end
  183. def test_clear_repeated_fields
  184. m = TestMessage.new
  185. m.repeated_int32.push(1)
  186. assert_equal [1], m.repeated_int32
  187. m.clear_repeated_int32
  188. assert_equal [], m.repeated_int32
  189. m.repeated_int32.push(1)
  190. assert_equal [1], m.repeated_int32
  191. TestMessage.descriptor.lookup('repeated_int32').clear(m)
  192. assert_equal [], m.repeated_int32
  193. m = OneofMessage.new
  194. m.a = "foo"
  195. assert_equal "foo", m.a
  196. assert m.has_my_oneof?
  197. assert_equal :a, m.my_oneof
  198. m.clear_a
  199. assert !m.has_my_oneof?
  200. m.a = "foobar"
  201. assert m.has_my_oneof?
  202. m.clear_my_oneof
  203. assert !m.has_my_oneof?
  204. m.a = "bar"
  205. assert_equal "bar", m.a
  206. assert m.has_my_oneof?
  207. OneofMessage.descriptor.lookup('a').clear(m)
  208. assert !m.has_my_oneof?
  209. end
  210. def test_initialization_map_errors
  211. e = assert_raise ArgumentError do
  212. TestMessage.new(:hello => "world")
  213. end
  214. assert_match(/hello/, e.message)
  215. e = assert_raise ArgumentError do
  216. MapMessage.new(:map_string_int32 => "hello")
  217. end
  218. assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32' (given String)."
  219. e = assert_raise ArgumentError do
  220. TestMessage.new(:repeated_uint32 => "hello")
  221. end
  222. assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32' (given String)."
  223. end
  224. def test_map_field
  225. m = MapMessage.new
  226. assert m.map_string_int32 == {}
  227. assert m.map_string_msg == {}
  228. m = MapMessage.new(
  229. :map_string_int32 => {"a" => 1, "b" => 2},
  230. :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
  231. "b" => TestMessage2.new(:foo => 2)},
  232. :map_string_enum => {"a" => :A, "b" => :B})
  233. assert m.map_string_int32.keys.sort == ["a", "b"]
  234. assert m.map_string_int32["a"] == 1
  235. assert m.map_string_msg["b"].foo == 2
  236. assert m.map_string_enum["a"] == :A
  237. m.map_string_int32["c"] = 3
  238. assert m.map_string_int32["c"] == 3
  239. m.map_string_msg["c"] = TestMessage2.new(:foo => 3)
  240. assert m.map_string_msg["c"] == TestMessage2.new(:foo => 3)
  241. m.map_string_msg.delete("b")
  242. m.map_string_msg.delete("c")
  243. assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
  244. assert_raise Google::Protobuf::TypeError do
  245. m.map_string_msg["e"] = TestMessage.new # wrong value type
  246. end
  247. # ensure nothing was added by the above
  248. assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
  249. m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
  250. assert_raise Google::Protobuf::TypeError do
  251. m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
  252. end
  253. assert_raise Google::Protobuf::TypeError do
  254. m.map_string_int32 = {}
  255. end
  256. assert_raise Google::Protobuf::TypeError do
  257. m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
  258. end
  259. end
  260. def test_map_field_with_symbol
  261. m = MapMessage.new
  262. assert m.map_string_int32 == {}
  263. assert m.map_string_msg == {}
  264. m = MapMessage.new(
  265. :map_string_int32 => {a: 1, "b" => 2},
  266. :map_string_msg => {a: TestMessage2.new(:foo => 1),
  267. b: TestMessage2.new(:foo => 10)})
  268. assert_equal 1, m.map_string_int32[:a]
  269. assert_equal 2, m.map_string_int32[:b]
  270. assert_equal 10, m.map_string_msg[:b].foo
  271. end
  272. def test_map_inspect
  273. m = MapMessage.new(
  274. :map_string_int32 => {"a" => 1, "b" => 2},
  275. :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
  276. "b" => TestMessage2.new(:foo => 2)},
  277. :map_string_enum => {"a" => :A, "b" => :B})
  278. # JRuby doesn't keep consistent ordering so check for either version
  279. 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}>"
  280. 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}>"
  281. inspect_result = m.inspect
  282. assert expected_a == inspect_result || expected_b == inspect_result, "Incorrect inspect result: #{inspect_result}"
  283. end
  284. def test_map_corruption
  285. # This pattern led to a crash in a previous version of upb/protobuf.
  286. m = MapMessage.new(map_string_int32: { "aaa" => 1 })
  287. m.map_string_int32['podid'] = 2
  288. m.map_string_int32['aaa'] = 3
  289. end
  290. def test_map_wrappers
  291. run_asserts = ->(m) {
  292. assert_equal 2.0, m.map_double[0].value
  293. assert_equal 4.0, m.map_float[0].value
  294. assert_equal 3, m.map_int32[0].value
  295. assert_equal 4, m.map_int64[0].value
  296. assert_equal 5, m.map_uint32[0].value
  297. assert_equal 6, m.map_uint64[0].value
  298. assert_equal true, m.map_bool[0].value
  299. assert_equal 'str', m.map_string[0].value
  300. assert_equal 'fun', m.map_bytes[0].value
  301. }
  302. m = proto_module::Wrapper.new(
  303. map_double: {0 => Google::Protobuf::DoubleValue.new(value: 2.0)},
  304. map_float: {0 => Google::Protobuf::FloatValue.new(value: 4.0)},
  305. map_int32: {0 => Google::Protobuf::Int32Value.new(value: 3)},
  306. map_int64: {0 => Google::Protobuf::Int64Value.new(value: 4)},
  307. map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 5)},
  308. map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 6)},
  309. map_bool: {0 => Google::Protobuf::BoolValue.new(value: true)},
  310. map_string: {0 => Google::Protobuf::StringValue.new(value: 'str')},
  311. map_bytes: {0 => Google::Protobuf::BytesValue.new(value: 'fun')},
  312. )
  313. run_asserts.call(m)
  314. serialized = proto_module::Wrapper::encode(m)
  315. m2 = proto_module::Wrapper::decode(serialized)
  316. run_asserts.call(m2)
  317. # Test the case where we are serializing directly from the parsed form
  318. # (before anything lazy is materialized).
  319. m3 = proto_module::Wrapper::decode(serialized)
  320. serialized2 = proto_module::Wrapper::encode(m3)
  321. m4 = proto_module::Wrapper::decode(serialized2)
  322. run_asserts.call(m4)
  323. # Test that the lazy form compares equal to the expanded form.
  324. m5 = proto_module::Wrapper::decode(serialized2)
  325. assert_equal m5, m
  326. end
  327. def test_map_wrappers_with_default_values
  328. run_asserts = ->(m) {
  329. assert_equal 0.0, m.map_double[0].value
  330. assert_equal 0.0, m.map_float[0].value
  331. assert_equal 0, m.map_int32[0].value
  332. assert_equal 0, m.map_int64[0].value
  333. assert_equal 0, m.map_uint32[0].value
  334. assert_equal 0, m.map_uint64[0].value
  335. assert_equal false, m.map_bool[0].value
  336. assert_equal '', m.map_string[0].value
  337. assert_equal '', m.map_bytes[0].value
  338. }
  339. m = proto_module::Wrapper.new(
  340. map_double: {0 => Google::Protobuf::DoubleValue.new(value: 0.0)},
  341. map_float: {0 => Google::Protobuf::FloatValue.new(value: 0.0)},
  342. map_int32: {0 => Google::Protobuf::Int32Value.new(value: 0)},
  343. map_int64: {0 => Google::Protobuf::Int64Value.new(value: 0)},
  344. map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 0)},
  345. map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 0)},
  346. map_bool: {0 => Google::Protobuf::BoolValue.new(value: false)},
  347. map_string: {0 => Google::Protobuf::StringValue.new(value: '')},
  348. map_bytes: {0 => Google::Protobuf::BytesValue.new(value: '')},
  349. )
  350. run_asserts.call(m)
  351. serialized = proto_module::Wrapper::encode(m)
  352. m2 = proto_module::Wrapper::decode(serialized)
  353. run_asserts.call(m2)
  354. # Test the case where we are serializing directly from the parsed form
  355. # (before anything lazy is materialized).
  356. m3 = proto_module::Wrapper::decode(serialized)
  357. serialized2 = proto_module::Wrapper::encode(m3)
  358. m4 = proto_module::Wrapper::decode(serialized2)
  359. run_asserts.call(m4)
  360. # Test that the lazy form compares equal to the expanded form.
  361. m5 = proto_module::Wrapper::decode(serialized2)
  362. assert_equal m5, m
  363. end
  364. def test_map_wrappers_with_no_value
  365. run_asserts = ->(m) {
  366. assert_equal 0.0, m.map_double[0].value
  367. assert_equal 0.0, m.map_float[0].value
  368. assert_equal 0, m.map_int32[0].value
  369. assert_equal 0, m.map_int64[0].value
  370. assert_equal 0, m.map_uint32[0].value
  371. assert_equal 0, m.map_uint64[0].value
  372. assert_equal false, m.map_bool[0].value
  373. assert_equal '', m.map_string[0].value
  374. assert_equal '', m.map_bytes[0].value
  375. }
  376. m = proto_module::Wrapper.new(
  377. map_double: {0 => Google::Protobuf::DoubleValue.new()},
  378. map_float: {0 => Google::Protobuf::FloatValue.new()},
  379. map_int32: {0 => Google::Protobuf::Int32Value.new()},
  380. map_int64: {0 => Google::Protobuf::Int64Value.new()},
  381. map_uint32: {0 => Google::Protobuf::UInt32Value.new()},
  382. map_uint64: {0 => Google::Protobuf::UInt64Value.new()},
  383. map_bool: {0 => Google::Protobuf::BoolValue.new()},
  384. map_string: {0 => Google::Protobuf::StringValue.new()},
  385. map_bytes: {0 => Google::Protobuf::BytesValue.new()},
  386. )
  387. run_asserts.call(m)
  388. serialized = proto_module::Wrapper::encode(m)
  389. m2 = proto_module::Wrapper::decode(serialized)
  390. run_asserts.call(m2)
  391. # Test the case where we are serializing directly from the parsed form
  392. # (before anything lazy is materialized).
  393. m3 = proto_module::Wrapper::decode(serialized)
  394. serialized2 = proto_module::Wrapper::encode(m3)
  395. m4 = proto_module::Wrapper::decode(serialized2)
  396. run_asserts.call(m4)
  397. end
  398. def test_concurrent_decoding
  399. o = Outer.new
  400. o.items[0] = Inner.new
  401. raw = Outer.encode(o)
  402. thds = 2.times.map do
  403. Thread.new do
  404. 100000.times do
  405. assert_equal o, Outer.decode(raw)
  406. end
  407. end
  408. end
  409. thds.map(&:join)
  410. end
  411. def test_map_encode_decode
  412. m = MapMessage.new(
  413. :map_string_int32 => {"a" => 1, "b" => 2},
  414. :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
  415. "b" => TestMessage2.new(:foo => 2)},
  416. :map_string_enum => {"a" => :A, "b" => :B})
  417. m2 = MapMessage.decode(MapMessage.encode(m))
  418. assert m == m2
  419. m3 = MapMessageWireEquiv.decode(MapMessage.encode(m))
  420. assert m3.map_string_int32.length == 2
  421. kv = {}
  422. m3.map_string_int32.map { |msg| kv[msg.key] = msg.value }
  423. assert kv == {"a" => 1, "b" => 2}
  424. kv = {}
  425. m3.map_string_msg.map { |msg| kv[msg.key] = msg.value }
  426. assert kv == {"a" => TestMessage2.new(:foo => 1),
  427. "b" => TestMessage2.new(:foo => 2)}
  428. end
  429. def test_protobuf_decode_json_ignore_unknown_fields
  430. m = TestMessage.decode_json({
  431. optional_string: "foo",
  432. not_in_message: "some_value"
  433. }.to_json, { ignore_unknown_fields: true })
  434. assert_equal m.optional_string, "foo"
  435. e = assert_raise Google::Protobuf::ParseError do
  436. TestMessage.decode_json({ not_in_message: "some_value" }.to_json)
  437. end
  438. assert_match(/No such field: not_in_message/, e.message)
  439. end
  440. #def test_json_quoted_string
  441. # m = TestMessage.decode_json(%q(
  442. # "optionalInt64": "1",,
  443. # }))
  444. # puts(m)
  445. # assert_equal 1, m.optional_int32
  446. #end
  447. def test_to_h
  448. m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'], :repeated_msg => [TestMessage2.new(:foo => 100)])
  449. expected_result = {
  450. :optional_bool=>true,
  451. :optional_bytes=>"",
  452. :optional_double=>-10.100001,
  453. :optional_enum=>:Default,
  454. :optional_float=>0.0,
  455. :optional_int32=>0,
  456. :optional_int64=>0,
  457. :optional_msg=>nil,
  458. :optional_msg2=>nil,
  459. :optional_proto2_submessage=>nil,
  460. :optional_string=>"foo",
  461. :optional_uint32=>0,
  462. :optional_uint64=>0,
  463. :repeated_bool=>[],
  464. :repeated_bytes=>[],
  465. :repeated_double=>[],
  466. :repeated_enum=>[],
  467. :repeated_float=>[],
  468. :repeated_int32=>[],
  469. :repeated_int64=>[],
  470. :repeated_msg=>[{:foo => 100}],
  471. :repeated_string=>["bar1", "bar2"],
  472. :repeated_uint32=>[],
  473. :repeated_uint64=>[]
  474. }
  475. assert_equal expected_result, m.to_h
  476. m = MapMessage.new(
  477. :map_string_int32 => {"a" => 1, "b" => 2},
  478. :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
  479. "b" => TestMessage2.new(:foo => 2)},
  480. :map_string_enum => {"a" => :A, "b" => :B})
  481. expected_result = {
  482. :map_string_int32 => {"a" => 1, "b" => 2},
  483. :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}},
  484. :map_string_enum => {"a" => :A, "b" => :B}
  485. }
  486. assert_equal expected_result, m.to_h
  487. end
  488. def test_json_maps
  489. m = MapMessage.new(:map_string_int32 => {"a" => 1})
  490. expected = {mapStringInt32: {a: 1}, mapStringMsg: {}, mapStringEnum: {}}
  491. expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}, map_string_enum: {}}
  492. assert_equal JSON.parse(MapMessage.encode_json(m, :emit_defaults=>true), :symbolize_names => true), expected
  493. json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true, :emit_defaults=>true)
  494. assert_equal JSON.parse(json, :symbolize_names => true), expected_preserve
  495. m2 = MapMessage.decode_json(MapMessage.encode_json(m))
  496. assert_equal m, m2
  497. end
  498. def test_json_maps_emit_defaults_submsg
  499. m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new(foo: 0)})
  500. expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}, mapStringEnum: {}}
  501. actual = MapMessage.encode_json(m, :emit_defaults => true)
  502. assert_equal JSON.parse(actual, :symbolize_names => true), expected
  503. end
  504. def test_json_emit_defaults_submsg
  505. m = TestSingularFields.new(singular_msg: proto_module::TestMessage2.new)
  506. expected = {
  507. singularInt32: 0,
  508. singularInt64: "0",
  509. singularUint32: 0,
  510. singularUint64: "0",
  511. singularBool: false,
  512. singularFloat: 0,
  513. singularDouble: 0,
  514. singularString: "",
  515. singularBytes: "",
  516. singularMsg: {},
  517. singularEnum: "Default",
  518. }
  519. actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
  520. assert_equal expected, JSON.parse(actual, :symbolize_names => true)
  521. end
  522. def test_respond_to
  523. msg = MapMessage.new
  524. assert msg.respond_to?(:map_string_int32)
  525. assert !msg.respond_to?(:bacon)
  526. end
  527. def test_file_descriptor
  528. file_descriptor = TestMessage.descriptor.file_descriptor
  529. assert nil != file_descriptor
  530. assert_equal "tests/basic_test.proto", file_descriptor.name
  531. assert_equal :proto3, file_descriptor.syntax
  532. file_descriptor = TestEnum.descriptor.file_descriptor
  533. assert nil != file_descriptor
  534. assert_equal "tests/basic_test.proto", file_descriptor.name
  535. assert_equal :proto3, file_descriptor.syntax
  536. end
  537. # Ruby 2.5 changed to raise FrozenError instead of RuntimeError
  538. FrozenErrorType = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5') ? RuntimeError : FrozenError
  539. def test_map_freeze
  540. m = proto_module::MapMessage.new
  541. m.map_string_int32['a'] = 5
  542. m.map_string_msg['b'] = proto_module::TestMessage2.new
  543. m.map_string_int32.freeze
  544. m.map_string_msg.freeze
  545. assert m.map_string_int32.frozen?
  546. assert m.map_string_msg.frozen?
  547. assert_raise(FrozenErrorType) { m.map_string_int32['foo'] = 1 }
  548. assert_raise(FrozenErrorType) { m.map_string_msg['bar'] = proto_module::TestMessage2.new }
  549. assert_raise(FrozenErrorType) { m.map_string_int32.delete('a') }
  550. assert_raise(FrozenErrorType) { m.map_string_int32.clear }
  551. end
  552. def test_map_length
  553. m = proto_module::MapMessage.new
  554. assert_equal 0, m.map_string_int32.length
  555. assert_equal 0, m.map_string_msg.length
  556. assert_equal 0, m.map_string_int32.size
  557. assert_equal 0, m.map_string_msg.size
  558. m.map_string_int32['a'] = 1
  559. m.map_string_int32['b'] = 2
  560. m.map_string_msg['a'] = proto_module::TestMessage2.new
  561. assert_equal 2, m.map_string_int32.length
  562. assert_equal 1, m.map_string_msg.length
  563. assert_equal 2, m.map_string_int32.size
  564. assert_equal 1, m.map_string_msg.size
  565. end
  566. def test_string_with_singleton_class_enabled
  567. str = 'foobar'
  568. # NOTE: Accessing a singleton class of an object changes its low level class representation
  569. # as far as the C API's CLASS_OF() method concerned, exposing the issue
  570. str.singleton_class
  571. m = proto_module::TestMessage.new(
  572. optional_string: str,
  573. optional_bytes: str
  574. )
  575. assert_equal str, m.optional_string
  576. assert_equal str, m.optional_bytes
  577. end
  578. def test_utf8
  579. m = proto_module::TestMessage.new(
  580. optional_string: "µpb",
  581. )
  582. m2 = proto_module::TestMessage.decode(proto_module::TestMessage.encode(m))
  583. assert_equal m2, m
  584. end
  585. def test_map_fields_respond_to? # regression test for issue 9202
  586. msg = proto_module::MapMessage.new
  587. assert msg.respond_to?(:map_string_int32=)
  588. msg.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
  589. assert msg.respond_to?(:map_string_int32)
  590. assert_equal( Google::Protobuf::Map.new(:string, :int32), msg.map_string_int32 )
  591. assert msg.respond_to?(:clear_map_string_int32)
  592. msg.clear_map_string_int32
  593. assert !msg.respond_to?(:has_map_string_int32?)
  594. assert_raise NoMethodError do
  595. msg.has_map_string_int32?
  596. end
  597. assert !msg.respond_to?(:map_string_int32_as_value)
  598. assert_raise NoMethodError do
  599. msg.map_string_int32_as_value
  600. end
  601. assert !msg.respond_to?(:map_string_int32_as_value=)
  602. assert_raise NoMethodError do
  603. msg.map_string_int32_as_value = :boom
  604. end
  605. end
  606. end
  607. def test_oneof_fields_respond_to? # regression test for issue 9202
  608. msg = proto_module::OneofMessage.new
  609. # `has_` prefix + "?" suffix actions should only work for oneofs fields.
  610. assert msg.has_my_oneof?
  611. assert msg.respond_to? :has_my_oneof?
  612. assert !msg.respond_to?( :has_a? )
  613. assert_raise NoMethodError do
  614. msg.has_a?
  615. end
  616. assert !msg.respond_to?( :has_b? )
  617. assert_raise NoMethodError do
  618. msg.has_b?
  619. end
  620. assert !msg.respond_to?( :has_c? )
  621. assert_raise NoMethodError do
  622. msg.has_c?
  623. end
  624. assert !msg.respond_to?( :has_d? )
  625. assert_raise NoMethodError do
  626. msg.has_d?
  627. end
  628. end
  629. end