|  | @@ -0,0 +1,262 @@
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @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);
 | 
	
		
			
				|  |  | +  });
 | 
	
		
			
				|  |  | +});
 |