|  | @@ -33,6 +33,8 @@ package com.google.protobuf;
 | 
	
		
			
				|  |  |  import com.google.protobuf.nano.CodedInputByteBufferNano;
 | 
	
		
			
				|  |  |  import com.google.protobuf.nano.EnumClassNanoMultiple;
 | 
	
		
			
				|  |  |  import com.google.protobuf.nano.EnumClassNanos;
 | 
	
		
			
				|  |  | +import com.google.protobuf.nano.EnumValidity;
 | 
	
		
			
				|  |  | +import com.google.protobuf.nano.EnumValidityAccessors;
 | 
	
		
			
				|  |  |  import com.google.protobuf.nano.Extensions;
 | 
	
		
			
				|  |  |  import com.google.protobuf.nano.Extensions.AnotherMessage;
 | 
	
		
			
				|  |  |  import com.google.protobuf.nano.Extensions.MessageWithGroup;
 | 
	
	
		
			
				|  | @@ -2092,6 +2094,126 @@ public class NanoTest extends TestCase {
 | 
	
		
			
				|  |  |      assertEquals(nestedMsg2.bb, newMsg.repeatedNestedMessage[2].bb);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Tests that invalid enum values from the wire are not accepted.
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  public void testNanoEnumValidity() throws Exception {
 | 
	
		
			
				|  |  | +    final int invalid = 120;
 | 
	
		
			
				|  |  | +    final int alsoInvalid = 121;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    EnumValidity.M m = new EnumValidity.M();
 | 
	
		
			
				|  |  | +    // Sanity check & baseline of the assertions for the first case below.
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidity.E.default_, m.optionalE);
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidity.E.BAZ, m.defaultE);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    m.optionalE = invalid;
 | 
	
		
			
				|  |  | +    m.defaultE = invalid;
 | 
	
		
			
				|  |  | +    // E contains all valid values
 | 
	
		
			
				|  |  | +    m.repeatedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR};
 | 
	
		
			
				|  |  | +    m.packedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ};
 | 
	
		
			
				|  |  | +    // E2 contains some invalid values
 | 
	
		
			
				|  |  | +    m.repeatedE2 = new int[] {invalid, EnumValidity.E.BAR, alsoInvalid};
 | 
	
		
			
				|  |  | +    m.packedE2 = new int[] {EnumValidity.E.FOO, invalid, alsoInvalid};
 | 
	
		
			
				|  |  | +    // E3 contains all invalid values
 | 
	
		
			
				|  |  | +    m.repeatedE3 = new int[] {invalid, invalid};
 | 
	
		
			
				|  |  | +    m.packedE3 = new int[] {alsoInvalid, alsoInvalid};
 | 
	
		
			
				|  |  | +    byte[] serialized = MessageNano.toByteArray(m);
 | 
	
		
			
				|  |  | +    // Sanity check that we do have all data in the byte array.
 | 
	
		
			
				|  |  | +    assertEquals(31, serialized.length);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Test 1: tests that invalid values aren't included in the deserialized message.
 | 
	
		
			
				|  |  | +    EnumValidity.M deserialized = MessageNano.mergeFrom(new EnumValidity.M(), serialized);
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidity.E.default_, deserialized.optionalE);
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidity.E.BAZ, deserialized.defaultE);
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(
 | 
	
		
			
				|  |  | +        new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR}, deserialized.repeatedE));
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(
 | 
	
		
			
				|  |  | +        new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ}, deserialized.packedE));
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(
 | 
	
		
			
				|  |  | +        new int[] {EnumValidity.E.BAR}, deserialized.repeatedE2));
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(
 | 
	
		
			
				|  |  | +        new int[] {EnumValidity.E.FOO}, deserialized.packedE2));
 | 
	
		
			
				|  |  | +    assertEquals(0, deserialized.repeatedE3.length);
 | 
	
		
			
				|  |  | +    assertEquals(0, deserialized.packedE3.length);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Test 2: tests that invalid values do not override previous values in the field, including
 | 
	
		
			
				|  |  | +    // arrays, including pre-existing invalid values.
 | 
	
		
			
				|  |  | +    deserialized.optionalE = EnumValidity.E.BAR;
 | 
	
		
			
				|  |  | +    deserialized.defaultE = alsoInvalid;
 | 
	
		
			
				|  |  | +    deserialized.repeatedE = new int[] {EnumValidity.E.BAZ};
 | 
	
		
			
				|  |  | +    deserialized.packedE = new int[] {EnumValidity.E.BAZ, alsoInvalid};
 | 
	
		
			
				|  |  | +    deserialized.repeatedE2 = new int[] {invalid, alsoInvalid};
 | 
	
		
			
				|  |  | +    deserialized.packedE2 = null;
 | 
	
		
			
				|  |  | +    deserialized.repeatedE3 = null;
 | 
	
		
			
				|  |  | +    deserialized.packedE3 = new int[0];
 | 
	
		
			
				|  |  | +    MessageNano.mergeFrom(deserialized, serialized);
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidity.E.BAR, deserialized.optionalE);
 | 
	
		
			
				|  |  | +    assertEquals(alsoInvalid, deserialized.defaultE);
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(
 | 
	
		
			
				|  |  | +        new int[] {EnumValidity.E.BAZ, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAR},
 | 
	
		
			
				|  |  | +        deserialized.repeatedE));
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(
 | 
	
		
			
				|  |  | +        new int[] {EnumValidity.E.BAZ, alsoInvalid, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAZ},
 | 
	
		
			
				|  |  | +        deserialized.packedE));
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(
 | 
	
		
			
				|  |  | +        new int[] {invalid, alsoInvalid, /* + */ EnumValidity.E.BAR},
 | 
	
		
			
				|  |  | +        deserialized.repeatedE2));
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(
 | 
	
		
			
				|  |  | +        new int[] {/* <null> + */ EnumValidity.E.FOO},
 | 
	
		
			
				|  |  | +        deserialized.packedE2));
 | 
	
		
			
				|  |  | +    assertNull(deserialized.repeatedE3); // null + all invalid == null
 | 
	
		
			
				|  |  | +    assertEquals(0, deserialized.packedE3.length); // empty + all invalid == empty
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Test 3: reading by alternative forms
 | 
	
		
			
				|  |  | +    EnumValidity.Alt alt = MessageNano.mergeFrom(new EnumValidity.Alt(), serialized);
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidity.E.BAR, // last valid value in m.repeatedE2
 | 
	
		
			
				|  |  | +        alt.repeatedE2AsOptional);
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(new int[] {EnumValidity.E.FOO}, alt.packedE2AsNonPacked));
 | 
	
		
			
				|  |  | +    assertEquals(0, alt.nonPackedE3AsPacked.length);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Tests the same as {@link #testNanoEnumValidity()} with accessor style. Repeated fields are
 | 
	
		
			
				|  |  | +   * not re-tested here because they are not affected by the accessor style.
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  public void testNanoEnumValidityAccessors() throws Exception {
 | 
	
		
			
				|  |  | +    final int invalid = 120;
 | 
	
		
			
				|  |  | +    final int alsoInvalid = 121;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    EnumValidityAccessors.M m = new EnumValidityAccessors.M();
 | 
	
		
			
				|  |  | +    // Sanity check & baseline of the assertions for the first case below.
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidityAccessors.default_, m.getOptionalE());
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidityAccessors.BAZ, m.getDefaultE());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    m.setOptionalE(invalid);
 | 
	
		
			
				|  |  | +    m.setDefaultE(invalid);
 | 
	
		
			
				|  |  | +    // Set repeatedE2 for Alt.repeatedE2AsOptional
 | 
	
		
			
				|  |  | +    m.repeatedE2 = new int[] {invalid, EnumValidityAccessors.BAR, alsoInvalid};
 | 
	
		
			
				|  |  | +    byte[] serialized = MessageNano.toByteArray(m);
 | 
	
		
			
				|  |  | +    // Sanity check that we do have all data in the byte array.
 | 
	
		
			
				|  |  | +    assertEquals(10, serialized.length);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Test 1: tests that invalid values aren't included in the deserialized message.
 | 
	
		
			
				|  |  | +    EnumValidityAccessors.M deserialized =
 | 
	
		
			
				|  |  | +        MessageNano.mergeFrom(new EnumValidityAccessors.M(), serialized);
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidityAccessors.default_, deserialized.getOptionalE());
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidityAccessors.BAZ, deserialized.getDefaultE());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Test 2: tests that invalid values do not override previous values in the field, including
 | 
	
		
			
				|  |  | +    // pre-existing invalid values.
 | 
	
		
			
				|  |  | +    deserialized.setOptionalE(EnumValidityAccessors.BAR);
 | 
	
		
			
				|  |  | +    deserialized.setDefaultE(alsoInvalid);
 | 
	
		
			
				|  |  | +    MessageNano.mergeFrom(deserialized, serialized);
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidityAccessors.BAR, deserialized.getOptionalE());
 | 
	
		
			
				|  |  | +    assertEquals(alsoInvalid, deserialized.getDefaultE());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Test 3: reading by alternative forms
 | 
	
		
			
				|  |  | +    EnumValidityAccessors.Alt alt =
 | 
	
		
			
				|  |  | +        MessageNano.mergeFrom(new EnumValidityAccessors.Alt(), serialized);
 | 
	
		
			
				|  |  | +    assertEquals(EnumValidityAccessors.BAR, // last valid value in m.repeatedE2
 | 
	
		
			
				|  |  | +        alt.getRepeatedE2AsOptional());
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    /**
 | 
	
		
			
				|  |  |     * Tests that code generation correctly wraps a single message into its outer
 | 
	
		
			
				|  |  |     * class. The class {@code SingleMessageNano} is imported from the outer
 | 
	
	
		
			
				|  | @@ -3248,12 +3370,16 @@ public class NanoTest extends TestCase {
 | 
	
		
			
				|  |  |      // Check that repeated fields with packable types can accept both packed and unpacked
 | 
	
		
			
				|  |  |      // serialized forms.
 | 
	
		
			
				|  |  |      NanoRepeatedPackables.NonPacked nonPacked = new NanoRepeatedPackables.NonPacked();
 | 
	
		
			
				|  |  | -    nonPacked.int32S = new int[] {1, 2, 3};
 | 
	
		
			
				|  |  | -    nonPacked.int64S = new long[] {4, 5, 6};
 | 
	
		
			
				|  |  | -    nonPacked.uint32S = new int[] {7, 8, 9};
 | 
	
		
			
				|  |  | -    nonPacked.uint64S = new long[] {10, 11, 12};
 | 
	
		
			
				|  |  | -    nonPacked.sint32S = new int[] {13, 14, 15};
 | 
	
		
			
				|  |  | -    nonPacked.sint64S = new long[] {16, 17, 18};
 | 
	
		
			
				|  |  | +    // Exaggerates the first values of varint-typed arrays. This is to test that the parsing code
 | 
	
		
			
				|  |  | +    // of packed fields handles non-packed data correctly. If the code incorrectly thinks it is
 | 
	
		
			
				|  |  | +    // reading from a packed tag, it will read the first value as the byte length of the field,
 | 
	
		
			
				|  |  | +    // and the large number will cause the input to go out of bounds, thus capturing the error.
 | 
	
		
			
				|  |  | +    nonPacked.int32S = new int[] {1000, 2, 3};
 | 
	
		
			
				|  |  | +    nonPacked.int64S = new long[] {4000, 5, 6};
 | 
	
		
			
				|  |  | +    nonPacked.uint32S = new int[] {7000, 8, 9};
 | 
	
		
			
				|  |  | +    nonPacked.uint64S = new long[] {10000, 11, 12};
 | 
	
		
			
				|  |  | +    nonPacked.sint32S = new int[] {13000, 14, 15};
 | 
	
		
			
				|  |  | +    nonPacked.sint64S = new long[] {16000, 17, 18};
 | 
	
		
			
				|  |  |      nonPacked.fixed32S = new int[] {19, 20, 21};
 | 
	
		
			
				|  |  |      nonPacked.fixed64S = new long[] {22, 23, 24};
 | 
	
		
			
				|  |  |      nonPacked.sfixed32S = new int[] {25, 26, 27};
 | 
	
	
		
			
				|  | @@ -3290,8 +3416,8 @@ public class NanoTest extends TestCase {
 | 
	
		
			
				|  |  |      nonPacked = MessageNano.mergeFrom(new NanoRepeatedPackables.NonPacked(), mixedSerialized);
 | 
	
		
			
				|  |  |      packed = MessageNano.mergeFrom(new NanoRepeatedPackables.Packed(), mixedSerialized);
 | 
	
		
			
				|  |  |      assertRepeatedPackablesEqual(nonPacked, packed);
 | 
	
		
			
				|  |  | -    assertTrue(Arrays.equals(new int[] {1, 2, 3, 1, 2, 3}, nonPacked.int32S));
 | 
	
		
			
				|  |  | -    assertTrue(Arrays.equals(new int[] {13, 14, 15, 13, 14, 15}, nonPacked.sint32S));
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(new int[] {1000, 2, 3, 1000, 2, 3}, nonPacked.int32S));
 | 
	
		
			
				|  |  | +    assertTrue(Arrays.equals(new int[] {13000, 14, 15, 13000, 14, 15}, nonPacked.sint32S));
 | 
	
		
			
				|  |  |      assertTrue(Arrays.equals(new int[] {25, 26, 27, 25, 26, 27}, nonPacked.sfixed32S));
 | 
	
		
			
				|  |  |      assertTrue(Arrays.equals(new boolean[] {false, true, false, true}, nonPacked.bools));
 | 
	
		
			
				|  |  |    }
 |