github.com/googleapis/api-linter@v1.65.2/rules/aip0148/declarative_friendly_fields_test.go (about) 1 // Copyright 2020 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 aip0148 16 17 import ( 18 "fmt" 19 "strings" 20 "testing" 21 22 "bitbucket.org/creachadair/stringset" 23 "github.com/googleapis/api-linter/rules/internal/testutils" 24 ) 25 26 func TestDeclarativeFriendlyFields(t *testing.T) { 27 for _, test := range []struct { 28 name string 29 skipped stringset.Set 30 }{ 31 {"Valid", stringset.New()}, 32 {"Name", stringset.New("name")}, 33 {"UID", stringset.New("uid")}, 34 {"DisplayName", stringset.New("display_name")}, 35 {"CreateTime", stringset.New("create_time")}, 36 {"UpdateTime", stringset.New("update_time")}, 37 {"DeleteTime", stringset.New("delete_time")}, 38 {"AllTimes", stringset.New("create_time", "update_time", "delete_time")}, 39 {"Randos", stringset.New("uid", "display_name")}, 40 } { 41 t.Run(test.name, func(t *testing.T) { 42 // Set up the string with the fields we will include. 43 fields := "" 44 cursor := 1 45 for fieldName, fieldType := range reqFields { 46 if !test.skipped.Contains(fieldName) { 47 fields += fmt.Sprintf(" %s %s = %d;\n", fieldType, fieldName, cursor) 48 cursor++ 49 } 50 } 51 52 // Create the potential problem object for the missing fields. 53 var problems testutils.Problems 54 if test.skipped.Len() == 1 { 55 f := test.skipped.Unordered()[0] 56 problems = testutils.Problems{{ 57 Message: fmt.Sprintf("must include the `%s %s` field", reqFields[f], f), 58 }} 59 } else if test.skipped.Len() > 1 { 60 missingFields := stringset.New() 61 for _, f := range test.skipped.Unordered() { 62 missingFields.Add(fmt.Sprintf("%s %s", reqFields[f], f)) 63 } 64 msg := "" 65 for _, f := range missingFields.Elements() { 66 msg += fmt.Sprintf(" - `%s`\n", f) 67 } 68 problems = testutils.Problems{{Message: strings.TrimSuffix(msg, "\n")}} 69 } 70 71 // Test against declarative-friendly and standard styles. 72 for _, subtest := range []struct { 73 name string 74 style string 75 problems testutils.Problems 76 }{ 77 {"DeclFriendly", "style: DECLARATIVE_FRIENDLY", problems}, 78 {"NotDeclFriendly", "", nil}, 79 } { 80 t.Run(subtest.name, func(t *testing.T) { 81 f := testutils.ParseProto3Tmpl(t, ` 82 import "google/api/resource.proto"; 83 import "google/protobuf/timestamp.proto"; 84 message Book { 85 option (google.api.resource) = { 86 type: "library.googleapis.com/Book" 87 pattern: "publishers/{publisher}/books/{book}" 88 {{.Style}} 89 }; 90 {{.Fields}} 91 } 92 `, struct { 93 Fields string 94 Style string 95 }{Fields: fields, Style: subtest.style}) 96 m := f.GetMessageTypes()[0] 97 got := declarativeFriendlyRequired.Lint(f) 98 if diff := subtest.problems.SetDescriptor(m).Diff(got); diff != "" { 99 t.Error(diff) 100 } 101 }) 102 } 103 }) 104 } 105 } 106 107 func TestDeclarativeFriendlyFieldsSingleton(t *testing.T) { 108 for _, test := range []struct { 109 name string 110 Fields string 111 want testutils.Problems 112 }{ 113 { 114 "InvalidNoCreateTime", `string name = 1; string display_name = 2; google.protobuf.Timestamp update_time = 3;`, 115 testutils.Problems{{Message: "create_time"}}, 116 }, 117 { 118 "ValidNoDeleteTimeNoUid", `string name = 1; string display_name = 2; ` + 119 `google.protobuf.Timestamp create_time = 3; google.protobuf.Timestamp update_time = 4;`, 120 nil, 121 }, 122 } { 123 t.Run(test.name, func(t *testing.T) { 124 f := testutils.ParseProto3Tmpl(t, ` 125 import "google/api/resource.proto"; 126 import "google/protobuf/timestamp.proto"; 127 message Book { 128 option (google.api.resource) = { 129 type: "library.googleapis.com/Settings" 130 pattern: "publishers/{publisher}/settings" 131 style: DECLARATIVE_FRIENDLY 132 }; 133 {{.Fields}} 134 } 135 `, test) 136 m := f.GetMessageTypes()[0] 137 got := declarativeFriendlyRequired.Lint(f) 138 if diff := test.want.SetDescriptor(m).Diff(got); diff != "" { 139 t.Error(diff) 140 } 141 }) 142 } 143 }