github.com/googleapis/api-linter@v1.65.2/rules/aip0121/no_mutable_cycles_test.go (about) 1 // Copyright 2023 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 aip0121 16 17 import ( 18 "testing" 19 20 "github.com/googleapis/api-linter/rules/internal/testutils" 21 ) 22 23 func TestNoMutableCycles(t *testing.T) { 24 25 for _, test := range []struct { 26 name string 27 BookExtensions, PublisherExtensions, LibraryExtensions, OtherPublisherExtensions string 28 problems testutils.Problems 29 }{ 30 { 31 "ValidNoCycle", 32 `[(google.api.resource_reference).type = "library.googleapis.com/Library"]`, 33 `[(google.api.resource_reference).type = "library.googleapis.com/Library"]`, 34 "", 35 "", 36 nil, 37 }, 38 { 39 "InvalidCycle", 40 `[(google.api.resource_reference).type = "library.googleapis.com/Publisher"]`, 41 `[(google.api.resource_reference).type = "library.googleapis.com/Book"]`, 42 "", 43 "", 44 testutils.Problems{{ 45 Message: "cycle", 46 }}, 47 }, 48 { 49 "InvalidSelfReferenceCycle", 50 "", 51 `[(google.api.resource_reference).type = "library.googleapis.com/Publisher"]`, 52 "", 53 "", 54 testutils.Problems{{ 55 Message: "cycle", 56 }}, 57 }, 58 { 59 "InvalidDeepCycle", 60 `[(google.api.resource_reference).type = "library.googleapis.com/Publisher"]`, 61 `[(google.api.resource_reference).type = "library.googleapis.com/Library"]`, 62 `[(google.api.resource_reference).type = "library.googleapis.com/Book"]`, 63 "", 64 testutils.Problems{{ 65 Message: "cycle", 66 }}, 67 }, 68 { 69 "InvalidDeepAndShallowCycles", 70 `[(google.api.resource_reference).type = "library.googleapis.com/Publisher"]`, 71 `[(google.api.resource_reference).type = "library.googleapis.com/Library"]`, 72 `[(google.api.resource_reference).type = "library.googleapis.com/Book"]`, 73 `[(google.api.resource_reference).type = "library.googleapis.com/Book"]`, 74 testutils.Problems{ 75 { 76 Message: "cycle", 77 }, 78 { 79 Message: "cycle", 80 }, 81 }, 82 }, 83 { 84 "ValidOutputOnlyCyclicReference", 85 `[(google.api.resource_reference).type = "library.googleapis.com/Publisher"]`, 86 `[ 87 (google.api.resource_reference).type = "library.googleapis.com/Book", 88 (google.api.field_behavior) = OUTPUT_ONLY 89 ]`, 90 "", 91 "", 92 nil, 93 }, 94 { 95 "ValidOutputOnlyDeepCyclicReference", 96 `[(google.api.resource_reference).type = "library.googleapis.com/Publisher"]`, 97 `[(google.api.resource_reference).type = "library.googleapis.com/Library"]`, 98 `[ 99 (google.api.resource_reference).type = "library.googleapis.com/Book", 100 (google.api.field_behavior) = OUTPUT_ONLY 101 ]`, 102 "", 103 nil, 104 }, 105 } { 106 t.Run(test.name, func(t *testing.T) { 107 f := testutils.ParseProto3Tmpl(t, ` 108 import "google/api/resource.proto"; 109 import "google/api/field_behavior.proto"; 110 message Book { 111 option (google.api.resource) = { 112 type: "library.googleapis.com/Book" 113 pattern: "publishers/{publisher}/books/{book}" 114 }; 115 string name = 1; 116 117 string resource = 2 {{.BookExtensions}}; 118 } 119 120 message Publisher { 121 option (google.api.resource) = { 122 type: "library.googleapis.com/Publisher" 123 pattern: "publishers/{publisher}" 124 }; 125 string name = 1; 126 127 string resource = 2 {{.PublisherExtensions}}; 128 129 string other_resource = 3 {{.OtherPublisherExtensions}}; 130 } 131 132 message Library { 133 option (google.api.resource) = { 134 type: "library.googleapis.com/Library" 135 pattern: "libraries/{library}" 136 }; 137 string name = 1; 138 139 string resource = 3 {{.LibraryExtensions}}; 140 } 141 `, test) 142 143 msg := f.FindMessage("Publisher") 144 want := test.problems 145 if len(want) >= 1 { 146 want[0].Descriptor = msg.FindFieldByName("resource") 147 } 148 if len(want) == 2 { 149 want[1].Descriptor = msg.FindFieldByName("other_resource") 150 } 151 // If this rule was run on the entire test file, there would be two 152 // findings, one for each resource in the cycle. To simplify that, 153 // we just lint one of the offending messages. 154 if diff := want.Diff(noMutableCycles.LintMessage(msg)); diff != "" { 155 t.Error(diff) 156 } 157 }) 158 } 159 }