public Location location() { return location.at(line + 1, pos - lineStart + 1); }
@Test public void reserved() { String proto = "" + "message Foo {\n" + " reserved 10, 12 to 14, 'foo';" + "}"; TypeElement message = MessageElement.builder(location.at(1, 1)) .name("Foo") .reserveds(ImmutableList.of(ReservedElement.create(location.at(2, 3), "", ImmutableList.<Object>of(10, Range.closed(12, 14), "foo")))) .build(); ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.of(message)) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void syntaxSpecified() throws Exception { String proto = "" + "syntax = \"proto3\";\n" + "message Foo {}"; ProtoFileElement expected = ProtoFileElement.builder(location) .syntax(ProtoFile.Syntax.PROTO_3) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(2, 1)) .name("Foo") .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void noWhitespace() { String proto = "message C {optional A.B ab = 1;}"; ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(1, 1)) .name("C").fields(ImmutableList.of(FieldElement.builder(location.at(1, 12)) .label(OPTIONAL) .type("A.B") .name("ab") .tag(1) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); } }
@Test public void syntaxMayFollowCommentsAndEmptyLines() throws Exception { String proto = "" + "/* comment 1 */\n" + "// comment 2\n" + "\n" + "syntax = \"proto3\";\n" + "message Foo {}"; ProtoFileElement expected = ProtoFileElement.builder(location) .syntax(ProtoFile.Syntax.PROTO_3) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(5, 1)) .name("Foo") .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void extendInMessage() throws Exception { String proto = "" + "message Bar {\n" + " extend Foo {\n" + " optional Bar bar = 126;\n" + " }\n" + "}"; ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(1, 1)).name("Bar").build())) .extendDeclarations(ImmutableList.of( ExtendElement.builder(location.at(2, 3)) .name("Foo") .fields(ImmutableList.of( FieldElement.builder(location.at(3, 5)) .label(OPTIONAL) .type("Bar") .name("bar") .tag(126) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void fqcnExtendInMessage() throws Exception { String proto = "" + "message Bar {\n" + " extend example.Foo {\n" + " optional Bar bar = 126;\n" + " }\n" + "}"; ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(1, 1)).name("Bar").build())) .extendDeclarations(ImmutableList.of( ExtendElement.builder(location.at(2, 3)) .name("example.Foo") .fields(ImmutableList.of( FieldElement.builder(location.at(3, 5)) .label(OPTIONAL) .type("Bar") .name("bar") .tag(126) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void simpleWithExtendsToSchema() { ProtoFileElement file = ProtoFileElement.builder(location) .extendDeclarations(ImmutableList.of( ExtendElement.builder(location.at(5, 1)).name("Extend").build())) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location) .name("Message") .build())) .build(); String expected = "" + "// file.proto\n" + "\n" + "message Message {}\n" + "\n" + "extend Extend {}\n"; assertThat(file.toSchema()).isEqualTo(expected); }
@Test public void proto3MessageFieldsPermitRepeated() throws Exception { String proto = "" + "syntax = \"proto3\";\n" + "message Message {\n" + " repeated string a = 1;\n" + "}"; ProtoFileElement expected = ProtoFileElement.builder(location) .syntax(ProtoFile.Syntax.PROTO_3) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(2, 1)) .name("Message") .fields(ImmutableList.of( FieldElement.builder(location.at(3, 3)) .label(REPEATED) .type("string") .name("a") .tag(1) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void extend() throws Exception { String proto = "" + "// Extends Foo\n" + "extend Foo {\n" + " optional int32 bar = 126;\n" + "}"; ProtoFileElement expected = ProtoFileElement.builder(location) .extendDeclarations(ImmutableList.of( ExtendElement.builder(location.at(2, 1)) .name("Foo") .documentation("Extends Foo") .fields(ImmutableList.of( FieldElement.builder(location.at(3, 3)) .label(OPTIONAL) .type("int32") .name("bar") .tag(126) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void proto3ExtensionFieldsPermitRepeated() throws Exception { String proto = "" + "syntax = \"proto3\";\n" + "message Message {\n" + "}\n" + "extend Message {\n" + " repeated string a = 1;\n" + "}"; ProtoFileElement expected = ProtoFileElement.builder(location) .syntax(ProtoFile.Syntax.PROTO_3) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(2, 1)) .name("Message") .build())) .extendDeclarations(ImmutableList.of( ExtendElement.builder(location.at(4, 1)) .name("Message") .fields(ImmutableList.of( FieldElement.builder(location.at(5, 3)) .label(REPEATED) .type("string") .name("a") .tag(1) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void packageDeclaration() throws Exception { String proto = "" + "package google.protobuf;\n" + "option java_package = \"com.google.protobuf\";\n" + "\n" + "// The protocol compiler can output a FileDescriptorSet containing the .proto\n" + "// files it parses.\n" + "message FileDescriptorSet {\n" + "}\n"; ProtoFileElement expected = ProtoFileElement.builder(location) .packageName("google.protobuf") .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(6, 1)) .name("FileDescriptorSet") .documentation("The protocol compiler can output a FileDescriptorSet containing " + "the .proto\nfiles it parses.") .build())) .options(ImmutableList.of( OptionElement.create("java_package", Kind.STRING, "com.google.protobuf"))) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void stringWithSingleQuotes() { String proto = "" + "message Foo {\n" + " optional string name = 1 [default = 'single\"quotes'];\n" + "}"; FieldElement field = FieldElement.builder(location.at(2, 3)) .label(OPTIONAL) .type("string") .name("name") .tag(1) .defaultValue("single\"quotes") .build(); TypeElement messageElement = MessageElement.builder(location.at(1, 1)) .name("Foo") .fields(ImmutableList.of(field)) .build(); ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.of(messageElement)) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
/** It looks like an option, but 'default' is special. It's missing from descriptor.proto! */ @Test public void defaultFieldOptionIsSpecial() { String proto = "" + "message Message {\n" + " required string a = 1 [default = \"b\", faulted = \"c\"];\n" + "}\n"; ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(1, 1)) .name("Message") .fields(ImmutableList.of( FieldElement.builder(location.at(2, 3)) .label(REQUIRED) .type("string") .name("a") .defaultValue("b") .options(ImmutableList.of( OptionElement.create("faulted", Kind.STRING, "c"))) .tag(1) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void fqcnExtendInMessageWithPackage() throws Exception { String proto = "" + "package kit.kat;\n" + "\n" + "message Bar {\n" + " extend example.Foo {\n" + " optional Bar bar = 126;\n" + " }\n" + "}"; ProtoFileElement expected = ProtoFileElement.builder(location) .packageName("kit.kat") .types(ImmutableList.<TypeElement>of(MessageElement.builder(location.at(3, 1)) .name("Bar") .build())) .extendDeclarations(ImmutableList.of( ExtendElement.builder(location.at(4, 3)) .name("example.Foo") .fields(ImmutableList.of( FieldElement.builder(location.at(5, 5)) .label(OPTIONAL) .type("Bar") .name("bar") .tag(126) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void adjacentStringsConcatenated() { String proto = "" + "message Foo {\n" + " optional string name = 1 [\n" + " default = \"concat \"\n" + " 'these '\n" + " \"please\"\n" + " ];\n" + "}"; FieldElement field = FieldElement.builder(location.at(2, 3)) .label(OPTIONAL) .type("string") .name("name") .tag(1) .defaultValue("concat these please") .build(); TypeElement messageElement = MessageElement.builder(location.at(1, 1)) .name("Foo") .fields(ImmutableList.of(field)) .build(); ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.of(messageElement)) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void proto3MessageFieldsDoNotRequireLabels() throws Exception { String proto = "" + "syntax = \"proto3\";\n" + "message Message {\n" + " string a = 1;\n" + " int32 b = 2;\n" + "}"; ProtoFileElement expected = ProtoFileElement.builder(location) .syntax(ProtoFile.Syntax.PROTO_3) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(2, 1)) .name("Message") .fields(ImmutableList.of( FieldElement.builder(location.at(3, 3)) .type("string") .name("a") .tag(1) .build(), FieldElement.builder(location.at(4, 3)) .type("int32") .name("b") .tag(2) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void defaultFieldWithParen() throws Exception { String proto = "" + "message Foo {\n" + " optional string claim_token = 2 [(squareup.redacted) = true];\n" + "}"; FieldElement field = FieldElement.builder(location.at(2, 3)) .label(OPTIONAL) .type("string") .name("claim_token") .tag(2) .options(ImmutableList.of( OptionElement.create("squareup.redacted", Kind.BOOLEAN, "true", true))) .build(); assertThat(field.options()).containsOnly( OptionElement.create("squareup.redacted", Kind.BOOLEAN, "true", true)); TypeElement messageElement = MessageElement.builder(location.at(1, 1)) .name("Foo") .fields(ImmutableList.of(field)) .build(); ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.of(messageElement)) .build(); assertThat(ProtoParser.parse(location, proto)) .isEqualTo(expected); }
@Test public void hexTag() throws Exception { String proto = "" + "message HexTag {\n" + " required string hex = 0x10;\n" + " required string uppercase_x_hex = 0X11;\n" + "}"; ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.<TypeElement>of( MessageElement.builder(location.at(1, 1)) .name("HexTag") .fields(ImmutableList.of( FieldElement.builder(location.at(2, 3)) .label(REQUIRED) .type("string") .name("hex") .tag(16) .build(), FieldElement.builder(location.at(3, 3)) .label(REQUIRED) .type("string") .name("uppercase_x_hex") .tag(17) .build())) .build())) .build(); assertThat(ProtoParser.parse(location, proto)).isEqualTo(expected); }
@Test public void defaultFieldWithStringEscapes() throws Exception { String proto = "" + "message Foo {\n" + " optional string name = 1 [\n" + " x = \"\\a\\b\\f\\n\\r\\t\\v\1f\01\001\11\011\111\\xe\\Xe\\xE\\xE\\x41\\X41\"\n" + " ];\n" + "}"; FieldElement field = FieldElement.builder(location.at(2, 3)) .label(OPTIONAL) .type("string") .name("name") .tag(1) .options(ImmutableList.of(OptionElement.create("x", Kind.STRING, "\u0007\b\f\n\r\t\u000b\u0001f\u0001\u0001\u0009\u0009I\u000e\u000e\u000e\u000eAA"))) .build(); assertThat(field.options()).containsOnly(OptionElement.create("x", Kind.STRING, "\u0007\b\f\n\r\t\u000b\u0001f\u0001\u0001\u0009\u0009I\u000e\u000e\u000e\u000eAA")); TypeElement messageElement = MessageElement.builder(location.at(1, 1)) .name("Foo") .fields(ImmutableList.of(field)) .build(); ProtoFileElement expected = ProtoFileElement.builder(location) .types(ImmutableList.of(messageElement)) .build(); assertThat(ProtoParser.parse(location, proto)) .isEqualTo(expected); }