kernel_compatibility_test.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /**
  2. * @fileoverview Tests to make sure Kernel can read data in a backward
  3. * compatible way even when protobuf schema changes according to the rules
  4. * defined in
  5. * https://developers.google.com/protocol-buffers/docs/proto#updating and
  6. * https://developers.google.com/protocol-buffers/docs/proto3#updating.
  7. *
  8. * third_party/protobuf/conformance/binary_json_conformance_suite.cc already
  9. * covers many compatibility tests, this file covers only the tests not covered
  10. * by binary_json_conformance_suite. Ultimately all of the tests in this file
  11. * should be moved to binary_json_conformance_suite.
  12. */
  13. goog.module('protobuf.runtime.KernelCompatibilityTest');
  14. goog.setTestOnly();
  15. const ByteString = goog.require('protobuf.ByteString');
  16. const Int64 = goog.require('protobuf.Int64');
  17. const Kernel = goog.require('protobuf.runtime.Kernel');
  18. const TestMessage = goog.require('protobuf.testing.binary.TestMessage');
  19. const {CHECK_CRITICAL_STATE} = goog.require('protobuf.internal.checks');
  20. /**
  21. * @param {...number} bytes
  22. * @return {!ArrayBuffer}
  23. */
  24. function createArrayBuffer(...bytes) {
  25. return new Uint8Array(bytes).buffer;
  26. }
  27. /**
  28. * Returns the Unicode character codes of a string.
  29. * @param {string} str
  30. * @return {!Array<number>}
  31. */
  32. function getCharacterCodes(str) {
  33. return Array.from(str, (c) => c.charCodeAt(0));
  34. }
  35. describe('optional -> repeated compatibility', () => {
  36. it('is maintained for scalars', () => {
  37. const oldAccessor = Kernel.createEmpty();
  38. oldAccessor.setInt32(1, 1);
  39. const serializedData = oldAccessor.serialize();
  40. expect(serializedData).toEqual(createArrayBuffer(0x8, 0x1));
  41. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  42. expect(newAccessor.getRepeatedInt32Size(1)).toEqual(1);
  43. expect(newAccessor.getRepeatedInt32Element(1, 0)).toEqual(1);
  44. });
  45. it('is maintained for messages', () => {
  46. const message = new TestMessage(Kernel.createEmpty());
  47. message.setInt32(1, 1);
  48. const oldAccessor = Kernel.createEmpty();
  49. oldAccessor.setMessage(1, message);
  50. const serializedData = oldAccessor.serialize();
  51. expect(serializedData).toEqual(createArrayBuffer(0xA, 0x2, 0x8, 0x1));
  52. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  53. expect(newAccessor.getRepeatedMessageSize(1, TestMessage.instanceCreator))
  54. .toEqual(1);
  55. expect(
  56. newAccessor.getRepeatedMessageElement(1, TestMessage.instanceCreator, 0)
  57. .serialize())
  58. .toEqual(message.serialize());
  59. });
  60. it('is maintained for bytes', () => {
  61. const message = new TestMessage(Kernel.createEmpty());
  62. message.setInt32(1, 1);
  63. const oldAccessor = Kernel.createEmpty();
  64. oldAccessor.setBytes(
  65. 1, ByteString.fromArrayBuffer(createArrayBuffer(0xA, 0xB)));
  66. const serializedData = oldAccessor.serialize();
  67. expect(serializedData).toEqual(createArrayBuffer(0xA, 0x2, 0xA, 0xB));
  68. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  69. expect(newAccessor.getRepeatedBytesSize(1)).toEqual(1);
  70. expect(newAccessor.getRepeatedBoolElement(1, 0))
  71. .toEqual(ByteString.fromArrayBuffer(createArrayBuffer(0xA, 0xB)));
  72. });
  73. it('is maintained for strings', () => {
  74. const oldAccessor = Kernel.createEmpty();
  75. oldAccessor.setString(1, 'hello');
  76. const serializedData = oldAccessor.serialize();
  77. expect(serializedData)
  78. .toEqual(createArrayBuffer(0xA, 0x5, 0x68, 0x65, 0x6C, 0x6C, 0x6F));
  79. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  80. expect(newAccessor.getRepeatedStringSize(1)).toEqual(1);
  81. expect(newAccessor.getRepeatedStringElement(1, 0)).toEqual('hello');
  82. });
  83. });
  84. describe('Kernel repeated -> optional compatibility', () => {
  85. it('is maintained for unpacked scalars', () => {
  86. const oldAccessor = Kernel.createEmpty();
  87. oldAccessor.addUnpackedInt32Element(1, 0);
  88. oldAccessor.addUnpackedInt32Element(1, 1);
  89. const serializedData = oldAccessor.serialize();
  90. expect(serializedData).toEqual(createArrayBuffer(0x8, 0x0, 0x8, 0x1));
  91. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  92. expect(newAccessor.getInt32WithDefault(1)).toEqual(1);
  93. expect(newAccessor.serialize()).toEqual(serializedData);
  94. });
  95. // repeated -> optional transformation is not supported for packed fields yet:
  96. // go/proto-schema-repeated
  97. it('is not maintained for packed scalars', () => {
  98. const oldAccessor = Kernel.createEmpty();
  99. oldAccessor.addPackedInt32Element(1, 0);
  100. oldAccessor.addPackedInt32Element(1, 1);
  101. const serializedData = oldAccessor.serialize();
  102. expect(serializedData).toEqual(createArrayBuffer(0xA, 0x2, 0x0, 0x1));
  103. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  104. if (CHECK_CRITICAL_STATE) {
  105. expect(() => newAccessor.getInt32WithDefault(1)).toThrow();
  106. }
  107. });
  108. it('is maintained for messages', () => {
  109. const message1 = new TestMessage(Kernel.createEmpty());
  110. message1.setInt32(1, 1);
  111. const message2 = new TestMessage(Kernel.createEmpty());
  112. message2.setInt32(1, 2);
  113. message2.setInt32(2, 3);
  114. const oldAccessor = Kernel.createEmpty();
  115. oldAccessor.addRepeatedMessageElement(
  116. 1, message1, TestMessage.instanceCreator);
  117. oldAccessor.addRepeatedMessageElement(
  118. 1, message2, TestMessage.instanceCreator);
  119. const serializedData = oldAccessor.serialize();
  120. expect(serializedData)
  121. .toEqual(createArrayBuffer(
  122. 0xA, 0x2, 0x8, 0x1, 0xA, 0x4, 0x8, 0x2, 0x10, 0x3));
  123. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  124. // Values from message1 and message2 have been merged
  125. const newMessage = newAccessor.getMessage(1, TestMessage.instanceCreator);
  126. expect(newMessage.getRepeatedInt32Size(1)).toEqual(2);
  127. expect(newMessage.getRepeatedInt32Element(1, 0)).toEqual(1);
  128. expect(newMessage.getRepeatedInt32Element(1, 1)).toEqual(2);
  129. expect(newMessage.getInt32WithDefault(2)).toEqual(3);
  130. expect(newMessage.serialize())
  131. .toEqual(createArrayBuffer(0x8, 0x1, 0x8, 0x2, 0x10, 0x3));
  132. });
  133. it('is maintained for bytes', () => {
  134. const oldAccessor = Kernel.createEmpty();
  135. oldAccessor.addRepeatedBytesElement(
  136. 1, ByteString.fromArrayBuffer(createArrayBuffer(0xA, 0xB)));
  137. oldAccessor.addRepeatedBytesElement(
  138. 1, ByteString.fromArrayBuffer(createArrayBuffer(0xC, 0xD)));
  139. const serializedData = oldAccessor.serialize();
  140. expect(serializedData)
  141. .toEqual(createArrayBuffer(0xA, 0x2, 0xA, 0xB, 0xA, 0x2, 0xC, 0xD));
  142. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  143. expect(newAccessor.getBytesWithDefault(1))
  144. .toEqual(ByteString.fromArrayBuffer(createArrayBuffer(0xC, 0xD)));
  145. expect(newAccessor.serialize()).toEqual(serializedData);
  146. });
  147. it('is maintained for strings', () => {
  148. const oldAccessor = Kernel.createEmpty();
  149. oldAccessor.addRepeatedStringElement(1, 'hello');
  150. oldAccessor.addRepeatedStringElement(1, 'world');
  151. const serializedData = oldAccessor.serialize();
  152. expect(serializedData)
  153. .toEqual(createArrayBuffer(
  154. 0xA, 0x5, ...getCharacterCodes('hello'), 0xA, 0x5,
  155. ...getCharacterCodes('world')));
  156. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  157. expect(newAccessor.getStringWithDefault(1)).toEqual('world');
  158. expect(newAccessor.serialize()).toEqual(serializedData);
  159. });
  160. });
  161. describe('Type change', () => {
  162. it('is supported for fixed32 -> sfixed32', () => {
  163. const oldAccessor = Kernel.createEmpty();
  164. oldAccessor.setFixed32(1, 4294967295);
  165. const serializedData = oldAccessor.serialize();
  166. expect(serializedData)
  167. .toEqual(createArrayBuffer(0xD, 0xFF, 0xFF, 0xFF, 0xFF));
  168. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  169. expect(newAccessor.getSfixed32WithDefault(1)).toEqual(-1);
  170. expect(newAccessor.serialize()).toEqual(serializedData);
  171. });
  172. it('is supported for sfixed32 -> fixed32', () => {
  173. const oldAccessor = Kernel.createEmpty();
  174. oldAccessor.setSfixed32(1, -1);
  175. const serializedData = oldAccessor.serialize();
  176. expect(serializedData)
  177. .toEqual(createArrayBuffer(0xD, 0xFF, 0xFF, 0xFF, 0xFF));
  178. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  179. expect(newAccessor.getFixed32WithDefault(1)).toEqual(4294967295);
  180. expect(newAccessor.serialize()).toEqual(serializedData);
  181. });
  182. it('is supported for fixed64 -> sfixed64', () => {
  183. const oldAccessor = Kernel.createEmpty();
  184. oldAccessor.setFixed64(1, Int64.fromHexString('0xFFFFFFFFFFFFFFFF'));
  185. const serializedData = oldAccessor.serialize();
  186. expect(serializedData)
  187. .toEqual(createArrayBuffer(
  188. 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF));
  189. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  190. expect(newAccessor.getSfixed64WithDefault(1)).toEqual(Int64.fromInt(-1));
  191. expect(newAccessor.serialize()).toEqual(serializedData);
  192. });
  193. it('is supported for sfixed64 -> fixed64', () => {
  194. const oldAccessor = Kernel.createEmpty();
  195. oldAccessor.setSfixed64(1, Int64.fromInt(-1));
  196. const serializedData = oldAccessor.serialize();
  197. expect(serializedData)
  198. .toEqual(createArrayBuffer(
  199. 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF));
  200. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  201. expect(newAccessor.getFixed64WithDefault(1))
  202. .toEqual(Int64.fromHexString('0xFFFFFFFFFFFFFFFF'));
  203. expect(newAccessor.serialize()).toEqual(serializedData);
  204. });
  205. it('is supported for bytes -> message', () => {
  206. const oldAccessor = Kernel.createEmpty();
  207. oldAccessor.setBytes(
  208. 1, ByteString.fromArrayBuffer(createArrayBuffer(0x8, 0x1)));
  209. const serializedData = oldAccessor.serialize();
  210. expect(serializedData).toEqual(createArrayBuffer(0xA, 0x2, 0x8, 0x1));
  211. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  212. const message = newAccessor.getMessage(1, TestMessage.instanceCreator);
  213. expect(message.getInt32WithDefault(1)).toEqual(1);
  214. expect(message.serialize()).toEqual(createArrayBuffer(0x8, 0x1));
  215. expect(newAccessor.serialize()).toEqual(serializedData);
  216. });
  217. it('is supported for message -> bytes', () => {
  218. const oldAccessor = Kernel.createEmpty();
  219. const message = new TestMessage(Kernel.createEmpty());
  220. message.setInt32(1, 1);
  221. oldAccessor.setMessage(1, message);
  222. const serializedData = oldAccessor.serialize();
  223. expect(serializedData).toEqual(createArrayBuffer(0xA, 0x2, 0x8, 0x1));
  224. const newAccessor = Kernel.fromArrayBuffer(serializedData);
  225. expect(newAccessor.getBytesWithDefault(1))
  226. .toEqual(ByteString.fromArrayBuffer(createArrayBuffer(0x8, 0x1)));
  227. expect(newAccessor.serialize()).toEqual(serializedData);
  228. });
  229. });