From fe1fdfe9d2419483723a1c2e0c150f4d2fbd9375 Mon Sep 17 00:00:00 2001 From: Phodal Huang Date: Fri, 25 Oct 2024 13:58:03 +0800 Subject: [PATCH] test(protobuf): add real-world test cases and enhance field construction #31 Add a new real-world test case for Protobuf parsing to ensure all fields and messages are correctly parsed. Additionally, improve the `constructField` function by including the field's modifiers in the `CodeField` object. --- .../ast/protobuf/ProtobufFullIdentListener.kt | 13 +-- .../ast/protobuf/ProtobufRealWorldTest.kt | 81 +++++++++++++++++++ 2 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 chapi-ast-protobuf/src/test/kotlin/chapi/ast/protobuf/ProtobufRealWorldTest.kt diff --git a/chapi-ast-protobuf/src/main/kotlin/chapi/ast/protobuf/ProtobufFullIdentListener.kt b/chapi-ast-protobuf/src/main/kotlin/chapi/ast/protobuf/ProtobufFullIdentListener.kt index d4796e11..b8607430 100644 --- a/chapi-ast-protobuf/src/main/kotlin/chapi/ast/protobuf/ProtobufFullIdentListener.kt +++ b/chapi-ast-protobuf/src/main/kotlin/chapi/ast/protobuf/ProtobufFullIdentListener.kt @@ -83,11 +83,14 @@ class ProtobufFullIdentListener(var fileName: String) : Protobuf3BaseListener() return codeDataStruct } - private fun constructField(child: Protobuf3Parser.FieldContext) = CodeField( - TypeType = child.type_().text, - TypeKey = child.fieldName().text, - TypeValue = child.fieldNumber().text - ) + private fun constructField(child: Protobuf3Parser.FieldContext): CodeField { + return CodeField( + TypeType = child.type_().text, + TypeKey = child.fieldName().text, + TypeValue = child.fieldNumber().text, + Modifiers = child.fieldLabel()?.text?.let { listOf(it) } ?: emptyList() + ) + } private fun constructEnum(child: Protobuf3Parser.EnumDefContext): CodeDataStruct { val name = child.enumName().text diff --git a/chapi-ast-protobuf/src/test/kotlin/chapi/ast/protobuf/ProtobufRealWorldTest.kt b/chapi-ast-protobuf/src/test/kotlin/chapi/ast/protobuf/ProtobufRealWorldTest.kt new file mode 100644 index 00000000..09010227 --- /dev/null +++ b/chapi-ast-protobuf/src/test/kotlin/chapi/ast/protobuf/ProtobufRealWorldTest.kt @@ -0,0 +1,81 @@ +package chapi.ast.protobuf + +import org.intellij.lang.annotations.Language +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class ProtobufRealWorldTest { + @Test + fun `should parse all field an message`() { + @Language("protobuf") + val protobufCode = """ +syntax = "proto3"; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; + +package bbq.interface.bullet.v1; + +option go_package = "api"; +option (gogoproto.goproto_getters_all) = false; + +message DataReport { + string app = 1 [(gogoproto.jsontag) = "mobi_app", (gogoproto.moretags)='form:"mobi_app"']; + string client = 2 [(gogoproto.jsontag) = "platform", (gogoproto.moretags)='form:"platform"']; + string version = 3 [(gogoproto.jsontag) = "version", (gogoproto.moretags)='form:"version"']; + string channel = 4 [(gogoproto.jsontag) = "channel", (gogoproto.moretags)='form:"channel"']; + string location = 5 [(gogoproto.jsontag) = "location", (gogoproto.moretags)='form:"location"']; + string query_id = 6 [(gogoproto.jsontag) = "query_id", (gogoproto.moretags)='form:"query_id"']; + string buvid = 7 [(gogoproto.jsontag) = "buvid", (gogoproto.moretags)='form:"buvid"']; + int64 svid = 8 [(gogoproto.jsontag) = "svid", (gogoproto.moretags)='form:"oid"']; + int32 total_duration = 9 [(gogoproto.jsontag) = "total_duration", (gogoproto.moretags)='form:"total_duration"']; + int32 play_duration = 10 [(gogoproto.jsontag) = "duration", (gogoproto.moretags)='form:"duration"']; + int32 data_type = 11 [(gogoproto.jsontag) = "data_type", (gogoproto.moretags)='form:"data_type"']; + int32 page = 12 [(gogoproto.jsontag) = "page_id", (gogoproto.moretags)='form:"page_id"']; + int32 module = 13 [(gogoproto.jsontag) = "module_id", (gogoproto.moretags)='form:"module_id"']; +} + +message ListBulletReq { + int64 oid = 1 [(gogoproto.moretags)='form:"oid"']; + int32 start_ms = 2 [(gogoproto.moretags)='form:"start_ms"']; + int32 end_ms = 3 [(gogoproto.moretags)='form:"end_ms"']; + string cursor_next = 4 [(gogoproto.moretags)='form:"cursor_next"']; + int64 mid = 5; +} + +message Bullet { + int64 id = 1; + int64 oid = 2[(gogoproto.moretags)='form:"oid"']; + int64 mid = 3[(gogoproto.jsontag) = "mid", (gogoproto.moretags)='form:"mid"']; + int32 offset_ms = 4[(gogoproto.jsontag) = "offset_ms", (gogoproto.moretags)='form:"offset_ms"']; + int32 offset = 5; + string content = 6[(gogoproto.jsontag) = "content", (gogoproto.moretags)='form:"content"']; + string cursor_value = 7[(gogoproto.jsontag) = "cursor_value,omitempty"]; +} + +message ListBulletReply { + bool has_more = 1 [(gogoproto.jsontag) = "has_more"]; + repeated Bullet list = 2 [(gogoproto.jsontag) = "list,omitempty"]; +} + +""" + val filePath = "path/to/file.proto" + val analyser = ProtobufAnalyser() + + val codeContainer = analyser.analysis(protobufCode, filePath) + + // SHOULD INCLUDE 4 DataStructures + assertEquals(4, codeContainer.DataStructures.size) + + // first DataStructure include 13 fields + assertEquals(13, codeContainer.DataStructures[0].Fields.size) + + // second DataStructure include 5 fields + assertEquals(5, codeContainer.DataStructures[1].Fields.size) + + // third DataStructure include 7 fields + assertEquals(7, codeContainer.DataStructures[2].Fields.size) + + // fourth DataStructure include 2 fields + assertEquals(2, codeContainer.DataStructures[3].Fields.size) + } +}