github.com/googleapis/api-linter@v1.65.2/rules/internal/testutils/parse.go (about) 1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package testutils 16 17 import ( 18 "bytes" 19 "fmt" 20 "strings" 21 "testing" 22 "text/template" 23 24 "github.com/jhump/protoreflect/desc" 25 "github.com/jhump/protoreflect/desc/protoparse" 26 "github.com/lithammer/dedent" 27 28 // These imports cause the common protos to be registered with 29 // the protocol buffer registry, and therefore make the call to 30 // `proto.FileDescriptor` work for the imported files. 31 _ "cloud.google.com/go/longrunning/autogen/longrunningpb" 32 _ "google.golang.org/genproto/googleapis/api/annotations" 33 _ "google.golang.org/genproto/googleapis/type/date" 34 _ "google.golang.org/genproto/googleapis/type/datetime" 35 _ "google.golang.org/genproto/googleapis/type/timeofday" 36 ) 37 38 // ParseProtoStrings parses a map representing a proto files, and returns 39 // a slice of FileDescriptors. 40 // 41 // It dedents the string before parsing. 42 func ParseProtoStrings(t *testing.T, src map[string]string) map[string]*desc.FileDescriptor { 43 filenames := []string{} 44 for k, v := range src { 45 filenames = append(filenames, k) 46 src[k] = strings.TrimSpace(dedent.Dedent(v)) 47 } 48 49 // Parse the file. 50 parser := protoparse.Parser{ 51 Accessor: protoparse.FileContentsFromMap(src), 52 IncludeSourceCodeInfo: true, 53 LookupImport: desc.LoadFileDescriptor, 54 } 55 fds, err := parser.ParseFiles(filenames...) 56 if err != nil { 57 t.Fatalf("%v", err) 58 } 59 answer := map[string]*desc.FileDescriptor{} 60 for _, fd := range fds { 61 answer[fd.GetName()] = fd 62 } 63 return answer 64 } 65 66 // ParseProto3String parses a string representing a proto file, and returns 67 // a FileDescriptor. 68 // 69 // It adds the `syntax = "proto3";` line to the beginning of the file and 70 // chooses a filename, and then calls ParseProtoStrings. 71 func ParseProto3String(t *testing.T, src string) *desc.FileDescriptor { 72 return ParseProtoStrings(t, map[string]string{ 73 "test.proto": fmt.Sprintf( 74 "syntax = \"proto3\";\n\n%s", 75 strings.TrimSpace(dedent.Dedent(src)), 76 ), 77 })["test.proto"] 78 } 79 80 // ParseProto3Tmpl parses a template string representing a proto file, and 81 // returns a FileDescriptor. 82 // 83 // It parses the template using Go's text/template Parse function, and then 84 // calls ParseProto3String. 85 func ParseProto3Tmpl(t *testing.T, src string, data interface{}) *desc.FileDescriptor { 86 return ParseProto3Tmpls(t, map[string]string{ 87 "test.proto": src, 88 }, data)["test.proto"] 89 } 90 91 // ParseProto3Tmpls parses template strings representing a proto file, 92 // and returns FileDescriptors. 93 // 94 // It parses the template using Go's text/template Parse function, and then 95 // calls ParseProto3Strings. 96 func ParseProto3Tmpls(t *testing.T, srcs map[string]string, data interface{}) map[string]*desc.FileDescriptor { 97 strs := map[string]string{} 98 for fn, src := range srcs { 99 // Create a new template object. 100 tmpl, err := template.New("test").Parse(src) 101 if err != nil { 102 t.Fatalf("Unable to parse Go template: %v", err) 103 } 104 105 // Execute the template and write the results to a bytes representing 106 // the desired proto. 107 var protoBytes bytes.Buffer 108 err = tmpl.Execute(&protoBytes, data) 109 if err != nil { 110 t.Fatalf("Unable to execute Go template: %v", err) 111 } 112 113 // Add the proto to the map to send to parse strings. 114 strs[fn] = fmt.Sprintf("syntax = %q;\n\n%s", "proto3", protoBytes.String()) 115 } 116 117 // Parse the proto as a string. 118 return ParseProtoStrings(t, strs) 119 }