|  | /** | 
|  | * @fileoverview Tests for message_set.js. | 
|  | */ | 
|  | goog.module('protobuf.runtime.MessageSetTest'); | 
|  |  | 
|  | goog.setTestOnly(); | 
|  |  | 
|  | const Kernel = goog.require('protobuf.runtime.Kernel'); | 
|  | const MessageSet = goog.require('protobuf.runtime.MessageSet'); | 
|  | const TestMessage = goog.require('protobuf.testing.binary.TestMessage'); | 
|  |  | 
|  | /** | 
|  | * @param {...number} bytes | 
|  | * @return {!ArrayBuffer} | 
|  | */ | 
|  | function createArrayBuffer(...bytes) { | 
|  | return new Uint8Array(bytes).buffer; | 
|  | } | 
|  |  | 
|  | describe('MessageSet does', () => { | 
|  | it('returns no messages for empty set', () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | expect(messageSet.getMessageOrNull(12345, TestMessage.instanceCreator)) | 
|  | .toBeNull(); | 
|  | }); | 
|  |  | 
|  | it('returns no kernel for empty set', () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | expect(messageSet.getMessageAccessorOrNull(12345)).toBeNull(); | 
|  | }); | 
|  |  | 
|  | it('returns message that has been set', () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | const message = TestMessage.createEmpty(); | 
|  | messageSet.setMessage(12345, message); | 
|  | expect(messageSet.getMessageOrNull(12345, TestMessage.instanceCreator)) | 
|  | .toBe(message); | 
|  | }); | 
|  |  | 
|  | it('returns null for cleared message', () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | const message = TestMessage.createEmpty(); | 
|  | messageSet.setMessage(12345, message); | 
|  | messageSet.clearMessage(12345); | 
|  | expect(messageSet.getMessageAccessorOrNull(12345)).toBeNull(); | 
|  | }); | 
|  |  | 
|  | it('returns false for not present message', () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | expect(messageSet.hasMessage(12345)).toBe(false); | 
|  | }); | 
|  |  | 
|  | it('returns true for present message', () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | const message = TestMessage.createEmpty(); | 
|  | messageSet.setMessage(12345, message); | 
|  | expect(messageSet.hasMessage(12345)).toBe(true); | 
|  | }); | 
|  |  | 
|  | it('returns false for cleared message', () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | const message = TestMessage.createEmpty(); | 
|  | messageSet.setMessage(12345, message); | 
|  | messageSet.clearMessage(12345); | 
|  | expect(messageSet.hasMessage(12345)).toBe(false); | 
|  | }); | 
|  |  | 
|  | it('returns false for cleared message without it being present', () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | messageSet.clearMessage(12345); | 
|  | expect(messageSet.hasMessage(12345)).toBe(false); | 
|  | }); | 
|  |  | 
|  | const createMessageSet = () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | const message = TestMessage.createEmpty(); | 
|  | message.setInt32(1, 2); | 
|  | messageSet.setMessage(12345, message); | 
|  |  | 
|  |  | 
|  | const parsedKernel = | 
|  | Kernel.fromArrayBuffer(messageSet.internalGetKernel().serialize()); | 
|  | return MessageSet.fromKernel(parsedKernel); | 
|  | }; | 
|  |  | 
|  | it('pass through pivot for getMessageOrNull', () => { | 
|  | const messageSet = createMessageSet(); | 
|  | const message = | 
|  | messageSet.getMessageOrNull(12345, TestMessage.instanceCreator, 2); | 
|  | expect(message.internalGetKernel().getPivot()).toBe(2); | 
|  | }); | 
|  |  | 
|  | it('pass through pivot for getMessageAttach', () => { | 
|  | const messageSet = createMessageSet(); | 
|  | const message = | 
|  | messageSet.getMessageAttach(12345, TestMessage.instanceCreator, 2); | 
|  | expect(message.internalGetKernel().getPivot()).toBe(2); | 
|  | }); | 
|  |  | 
|  | it('pass through pivot for getMessageAccessorOrNull', () => { | 
|  | const messageSet = createMessageSet(); | 
|  | const kernel = messageSet.getMessageAccessorOrNull(12345, 2); | 
|  | expect(kernel.getPivot()).toBe(2); | 
|  | }); | 
|  |  | 
|  | it('pick the last value in the stream', () => { | 
|  | const arrayBuffer = createArrayBuffer( | 
|  | 0x52,  // Tag (field:10, length delimited) | 
|  | 0x14,  // Length of 20 bytes | 
|  | 0x0B,  // Start group fieldnumber 1 | 
|  | 0x10,  // Tag (field 2, varint) | 
|  | 0xB9,  // 12345 | 
|  | 0x60,  // 12345 | 
|  | 0x1A,  // Tag (field 3, length delimited) | 
|  | 0x03,  // length 3 | 
|  | 0xA0,  // Tag (fieldnumber 20, varint) | 
|  | 0x01,  // Tag (fieldnumber 20, varint) | 
|  | 0x1E,  // 30 | 
|  | 0x0C,  // Stop Group field number 1 | 
|  | // second group | 
|  | 0x0B,  // Start group fieldnumber 1 | 
|  | 0x10,  // Tag (field 2, varint) | 
|  | 0xB9,  // 12345 | 
|  | 0x60,  // 12345 | 
|  | 0x1A,  // Tag (field 3, length delimited) | 
|  | 0x03,  // length 3 | 
|  | 0xA0,  // Tag (fieldnumber 20, varint) | 
|  | 0x01,  // Tag (fieldnumber 20, varint) | 
|  | 0x01,  // 1 | 
|  | 0x0C   // Stop Group field number 1 | 
|  | ); | 
|  |  | 
|  | const outerMessage = Kernel.fromArrayBuffer(arrayBuffer); | 
|  |  | 
|  | const messageSet = outerMessage.getMessage(10, MessageSet.fromKernel); | 
|  |  | 
|  | const message = | 
|  | messageSet.getMessageOrNull(12345, TestMessage.instanceCreator); | 
|  | expect(message.getInt32WithDefault(20)).toBe(1); | 
|  | }); | 
|  |  | 
|  | it('removes duplicates when read', () => { | 
|  | const arrayBuffer = createArrayBuffer( | 
|  | 0x52,  // Tag (field:10, length delimited) | 
|  | 0x14,  // Length of 20 bytes | 
|  | 0x0B,  // Start group fieldnumber 1 | 
|  | 0x10,  // Tag (field 2, varint) | 
|  | 0xB9,  // 12345 | 
|  | 0x60,  // 12345 | 
|  | 0x1A,  // Tag (field 3, length delimited) | 
|  | 0x03,  // length 3 | 
|  | 0xA0,  // Tag (fieldnumber 20, varint) | 
|  | 0x01,  // Tag (fieldnumber 20, varint) | 
|  | 0x1E,  // 30 | 
|  | 0x0C,  // Stop Group field number 1 | 
|  | // second group | 
|  | 0x0B,  // Start group fieldnumber 1 | 
|  | 0x10,  // Tag (field 2, varint) | 
|  | 0xB9,  // 12345 | 
|  | 0x60,  // 12345 | 
|  | 0x1A,  // Tag (field 3, length delimited) | 
|  | 0x03,  // length 3 | 
|  | 0xA0,  // Tag (fieldnumber 20, varint) | 
|  | 0x01,  // Tag (fieldnumber 20, varint) | 
|  | 0x01,  // 1 | 
|  | 0x0C   // Stop Group field number 1 | 
|  | ); | 
|  |  | 
|  |  | 
|  | const outerMessage = Kernel.fromArrayBuffer(arrayBuffer); | 
|  | outerMessage.getMessageAttach(10, MessageSet.fromKernel); | 
|  |  | 
|  | expect(outerMessage.serialize()) | 
|  | .toEqual(createArrayBuffer( | 
|  | 0x52,  // Tag (field:10, length delimited) | 
|  | 0x0A,  // Length of 10 bytes | 
|  | 0x0B,  // Start group fieldnumber 1 | 
|  | 0x10,  // Tag (field 2, varint) | 
|  | 0xB9,  // 12345 | 
|  | 0x60,  // 12345 | 
|  | 0x1A,  // Tag (field 3, length delimited) | 
|  | 0x03,  // length 3 | 
|  | 0xA0,  // Tag (fieldnumber 20, varint) | 
|  | 0x01,  // Tag (fieldnumber 20, varint) | 
|  | 0x01,  // 1 | 
|  | 0x0C   // Stop Group field number 1 | 
|  | )); | 
|  | }); | 
|  |  | 
|  | it('allow for large typeIds', () => { | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | const message = TestMessage.createEmpty(); | 
|  | messageSet.setMessage(0xFFFFFFFE >>> 0, message); | 
|  | expect(messageSet.hasMessage(0xFFFFFFFE >>> 0)).toBe(true); | 
|  | }); | 
|  | }); | 
|  |  | 
|  | describe('Optional MessageSet does', () => { | 
|  | // message Bar { | 
|  | //  optional MessageSet mset = 10; | 
|  | //} | 
|  | // | 
|  | // message Foo { | 
|  | //  extend proto2.bridge.MessageSet { | 
|  | //    optional Foo message_set_extension = 12345; | 
|  | //  } | 
|  | //  optional int32 f20 = 20; | 
|  | //} | 
|  |  | 
|  | it('encode as a field', () => { | 
|  | const fooMessage = Kernel.createEmpty(); | 
|  | fooMessage.setInt32(20, 30); | 
|  |  | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | messageSet.setMessage(12345, TestMessage.instanceCreator(fooMessage)); | 
|  |  | 
|  | const barMessage = Kernel.createEmpty(); | 
|  | barMessage.setMessage(10, messageSet); | 
|  |  | 
|  | expect(barMessage.serialize()) | 
|  | .toEqual(createArrayBuffer( | 
|  | 0x52,  // Tag (field:10, length delimited) | 
|  | 0x0A,  // Length of 10 bytes | 
|  | 0x0B,  // Start group fieldnumber 1 | 
|  | 0x10,  // Tag (field 2, varint) | 
|  | 0xB9,  // 12345 | 
|  | 0x60,  // 12345 | 
|  | 0x1A,  // Tag (field 3, length delimited) | 
|  | 0x03,  // length 3 | 
|  | 0xA0,  // Tag (fieldnumber 20, varint) | 
|  | 0x01,  // Tag (fieldnumber 20, varint) | 
|  | 0x1E,  // 30 | 
|  | 0x0C   // Stop Group field number 1 | 
|  | )); | 
|  | }); | 
|  |  | 
|  | it('deserializes', () => { | 
|  | const fooMessage = Kernel.createEmpty(); | 
|  | fooMessage.setInt32(20, 30); | 
|  |  | 
|  | const messageSet = MessageSet.createEmpty(); | 
|  | messageSet.setMessage(12345, TestMessage.instanceCreator(fooMessage)); | 
|  |  | 
|  |  | 
|  | const barMessage = Kernel.createEmpty(); | 
|  | barMessage.setMessage(10, messageSet); | 
|  |  | 
|  | const arrayBuffer = barMessage.serialize(); | 
|  |  | 
|  | const barMessageParsed = Kernel.fromArrayBuffer(arrayBuffer); | 
|  | expect(barMessageParsed.hasFieldNumber(10)).toBe(true); | 
|  |  | 
|  | const messageSetParsed = | 
|  | barMessageParsed.getMessage(10, MessageSet.fromKernel); | 
|  |  | 
|  | const fooMessageParsed = | 
|  | messageSetParsed.getMessageOrNull(12345, TestMessage.instanceCreator) | 
|  | .internalGetKernel(); | 
|  |  | 
|  | expect(fooMessageParsed.getInt32WithDefault(20)).toBe(30); | 
|  | }); | 
|  | }); |