Add support for handling unknown protobuf fields.

This commit is contained in:
Greyson Parrelli
2020-08-20 16:05:50 -04:00
committed by Alex Hart
parent ffcb90da52
commit 2cf9eb69eb
15 changed files with 631 additions and 47 deletions

View File

@@ -0,0 +1,229 @@
package org.whispersystems.signalservice.api.util;
import com.google.protobuf.InvalidProtocolBufferException;
import org.junit.Assert;
import org.junit.Test;
import org.thoughtcrime.securesms.util.testprotos.TestInnerMessage;
import org.thoughtcrime.securesms.util.testprotos.TestInnerMessageWithNewString;
import org.thoughtcrime.securesms.util.testprotos.TestPerson;
import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewFieldOnMessage;
import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewMessage;
import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewRepeatedString;
import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewString;
import org.thoughtcrime.securesms.util.testprotos.TestPersonWithNewStringAndInt;
import org.whispersystems.signalservice.api.util.ProtoUtil;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class ProtoUtilTest {
@Test
public void hasUnknownFields_noUnknowns() {
TestPerson person = TestPerson.newBuilder()
.setName("Peter Parker")
.setAge(23)
.build();
assertFalse(ProtoUtil.hasUnknownFields(person));
}
@Test
public void hasUnknownFields_unknownString() throws InvalidProtocolBufferException {
TestPersonWithNewString person = TestPersonWithNewString.newBuilder()
.setName("Peter Parker")
.setAge(23)
.setJob("Reporter")
.build();
TestPerson personWithUnknowns = TestPerson.parseFrom(person.toByteArray());
assertTrue(ProtoUtil.hasUnknownFields(personWithUnknowns));
}
@Test
public void hasUnknownFields_multipleUnknowns() throws InvalidProtocolBufferException {
TestPersonWithNewStringAndInt person = TestPersonWithNewStringAndInt.newBuilder()
.setName("Peter Parker")
.setAge(23)
.setJob("Reporter")
.setSalary(75_000)
.build();
TestPerson personWithUnknowns = TestPerson.parseFrom(person.toByteArray());
assertTrue(ProtoUtil.hasUnknownFields(personWithUnknowns));
}
@Test
public void hasUnknownFields_unknownMessage() throws InvalidProtocolBufferException {
TestPersonWithNewMessage person = TestPersonWithNewMessage.newBuilder()
.setName("Peter Parker")
.setAge(23)
.setJob(TestPersonWithNewMessage.Job.newBuilder()
.setTitle("Reporter")
.setSalary(75_000))
.build();
TestPerson personWithUnknowns = TestPerson.parseFrom(person.toByteArray());
assertTrue(ProtoUtil.hasUnknownFields(personWithUnknowns));
}
@Test
public void hasUnknownFields_unknownInsideMessage() throws InvalidProtocolBufferException {
TestPersonWithNewFieldOnMessage person = TestPersonWithNewFieldOnMessage.newBuilder()
.setName("Peter Parker")
.setAge(23)
.setJob(TestPersonWithNewFieldOnMessage.Job.newBuilder()
.setTitle("Reporter")
.setSalary(75_000)
.setStartDate(100))
.build();
TestPersonWithNewMessage personWithUnknowns = TestPersonWithNewMessage.parseFrom(person.toByteArray());
assertTrue(ProtoUtil.hasUnknownFields(personWithUnknowns));
}
@Test
public void combineWithUnknownFields_noUnknowns() throws InvalidProtocolBufferException {
TestPerson personWithUnknowns = TestPerson.newBuilder()
.setName("Peter Parker")
.setAge(23)
.build();
TestPerson localRepresentation = TestPerson.newBuilder()
.setName("Spider-Man")
.setAge(23)
.build();
TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray());
TestPersonWithNewString reparsedPerson = TestPersonWithNewString.parseFrom(combinedWithUnknowns.toByteArray());
Assert.assertEquals("Spider-Man", reparsedPerson.getName());
Assert.assertEquals(23, reparsedPerson.getAge());
}
@Test
public void combineWithUnknownFields_appendedString() throws InvalidProtocolBufferException {
TestPersonWithNewString personWithUnknowns = TestPersonWithNewString.newBuilder()
.setName("Peter Parker")
.setAge(23)
.setJob("Reporter")
.build();
TestPerson localRepresentation = TestPerson.newBuilder()
.setName("Spider-Man")
.setAge(23)
.build();
TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray());
TestPersonWithNewString reparsedPerson = TestPersonWithNewString.parseFrom(combinedWithUnknowns.toByteArray());
Assert.assertEquals("Spider-Man", reparsedPerson.getName());
Assert.assertEquals(23, reparsedPerson.getAge());
Assert.assertEquals("Reporter", reparsedPerson.getJob());
}
@Test
public void combineWithUnknownFields_appendedRepeatedString() throws InvalidProtocolBufferException {
TestPersonWithNewRepeatedString personWithUnknowns = TestPersonWithNewRepeatedString.newBuilder()
.setName("Peter Parker")
.setAge(23)
.addJobs("Reporter")
.addJobs("Super Hero")
.build();
TestPerson localRepresentation = TestPerson.newBuilder()
.setName("Spider-Man")
.setAge(23)
.build();
TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray());
TestPersonWithNewRepeatedString reparsedPerson = TestPersonWithNewRepeatedString.parseFrom(combinedWithUnknowns.toByteArray());
Assert.assertEquals("Spider-Man", reparsedPerson.getName());
Assert.assertEquals(23, reparsedPerson.getAge());
Assert.assertEquals(2, reparsedPerson.getJobsCount());
Assert.assertEquals("Reporter", reparsedPerson.getJobs(0));
Assert.assertEquals("Super Hero", reparsedPerson.getJobs(1));
}
@Test
public void combineWithUnknownFields_appendedStringAndInt() throws InvalidProtocolBufferException {
TestPersonWithNewStringAndInt personWithUnknowns = TestPersonWithNewStringAndInt.newBuilder()
.setName("Peter Parker")
.setAge(23)
.setJob("Reporter")
.setSalary(75_000)
.build();
TestPerson localRepresentation = TestPerson.newBuilder()
.setName("Spider-Man")
.setAge(23)
.build();
TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray());
TestPersonWithNewStringAndInt reparsedPerson = TestPersonWithNewStringAndInt.parseFrom(combinedWithUnknowns.toByteArray());
Assert.assertEquals("Spider-Man", reparsedPerson.getName());
Assert.assertEquals(23, reparsedPerson.getAge());
Assert.assertEquals("Reporter", reparsedPerson.getJob());
Assert.assertEquals(75_000, reparsedPerson.getSalary());
}
@Test
public void combineWithUnknownFields_appendedMessage() throws InvalidProtocolBufferException {
TestPersonWithNewMessage personWithUnknowns = TestPersonWithNewMessage.newBuilder()
.setName("Peter Parker")
.setAge(23)
.setJob(TestPersonWithNewMessage.Job.newBuilder()
.setTitle("Reporter")
.setSalary(75_000))
.build();
TestPerson localRepresentation = TestPerson.newBuilder()
.setName("Spider-Man")
.setAge(23)
.build();
TestPerson combinedWithUnknowns = ProtoUtil.combineWithUnknownFields(localRepresentation, personWithUnknowns.toByteArray());
TestPersonWithNewMessage reparsedPerson = TestPersonWithNewMessage.parseFrom(combinedWithUnknowns.toByteArray());
Assert.assertEquals("Spider-Man", reparsedPerson.getName());
Assert.assertEquals(23, reparsedPerson.getAge());
Assert.assertEquals("Reporter", reparsedPerson.getJob().getTitle());
Assert.assertEquals(75_000, reparsedPerson.getJob().getSalary());
}
/**
* This isn't ideal behavior. This is more to show how something works. In the future, it'd be
* nice to support inner unknown fields.
*/
@Test
public void combineWithUnknownFields_innerMessagesUnknownsIgnored() throws InvalidProtocolBufferException {
TestInnerMessageWithNewString test = TestInnerMessageWithNewString.newBuilder()
.setInner(TestInnerMessageWithNewString.Inner.newBuilder()
.setA("a1")
.setB("b1")
.build())
.build();
TestInnerMessage localRepresentation = TestInnerMessage.newBuilder()
.setInner(TestInnerMessage.Inner.newBuilder()
.setA("a2")
.build())
.build();
TestInnerMessage combined = ProtoUtil.combineWithUnknownFields(localRepresentation, test.toByteArray());
TestInnerMessageWithNewString reparsedTest = TestInnerMessageWithNewString.parseFrom(combined.toByteArray());
Assert.assertEquals("a2", reparsedTest.getInner().getA());
Assert.assertEquals("", reparsedTest.getInner().getB());
}
}

View File

@@ -0,0 +1,70 @@
syntax = "proto3";
package signal;
option java_package = "org.thoughtcrime.securesms.util.testprotos";
option java_multiple_files = true;
message TestPerson {
string name = 1;
int32 age = 2;
}
message TestPersonWithNewString {
string name = 1;
int32 age = 2;
string job = 3;
}
message TestPersonWithNewRepeatedString {
string name = 1;
int32 age = 2;
repeated string jobs = 3;
}
message TestPersonWithNewStringAndInt {
string name = 1;
int32 age = 2;
string job = 3;
int32 salary = 4;
}
message TestPersonWithNewMessage {
message Job {
string title = 1;
uint32 salary = 2;
}
string name = 1;
int32 age = 2;
Job job = 3;
}
message TestPersonWithNewFieldOnMessage {
message Job {
string title = 1;
uint32 salary = 2;
uint64 startDate = 3;
}
string name = 1;
int32 age = 2;
Job job = 3;
}
message TestInnerMessage {
message Inner {
string a = 1;
}
Inner inner = 1;
}
message TestInnerMessageWithNewString {
message Inner {
string a = 1;
string b = 2;
}
Inner inner = 1;
}