1// Copyright 2019 Google Inc. All rights reserved. 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// http://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 15package proptools 16 17import ( 18 "reflect" 19 "testing" 20) 21 22type testType struct { 23 NoTag string 24 EmptyTag string `` 25 OtherTag string `foo:"bar"` 26 MatchingTag string `name:"value"` 27 ExtraValues string `name:"foo,value,bar"` 28 ExtraTags string `foo:"bar" name:"value"` 29} 30 31func TestHasTag(t *testing.T) { 32 tests := []struct { 33 field string 34 want bool 35 }{ 36 { 37 field: "NoTag", 38 want: false, 39 }, 40 { 41 field: "EmptyTag", 42 want: false, 43 }, 44 { 45 field: "OtherTag", 46 want: false, 47 }, 48 { 49 field: "MatchingTag", 50 want: true, 51 }, 52 { 53 field: "ExtraValues", 54 want: true, 55 }, 56 { 57 field: "ExtraTags", 58 want: true, 59 }, 60 } 61 for _, test := range tests { 62 t.Run(test.field, func(t *testing.T) { 63 field, _ := reflect.TypeOf(testType{}).FieldByName(test.field) 64 if got := HasTag(field, "name", "value"); got != test.want { 65 t.Errorf(`HasTag(%q, "name", "value") = %v, want %v`, field.Tag, got, test.want) 66 } 67 }) 68 } 69} 70 71func BenchmarkHasTag(b *testing.B) { 72 tests := []struct { 73 field string 74 }{ 75 { 76 field: "NoTag", 77 }, 78 { 79 field: "EmptyTag", 80 }, 81 { 82 field: "OtherTag", 83 }, 84 { 85 field: "MatchingTag", 86 }, 87 { 88 field: "ExtraValues", 89 }, 90 { 91 field: "ExtraTags", 92 }, 93 } 94 for _, test := range tests { 95 b.Run(test.field, func(b *testing.B) { 96 field, _ := reflect.TypeOf(testType{}).FieldByName(test.field) 97 for i := 0; i < b.N; i++ { 98 HasTag(field, "name", "value") 99 } 100 }) 101 } 102} 103 104func TestPropertyIndexesWithTag(t *testing.T) { 105 tests := []struct { 106 name string 107 ps interface{} 108 want [][]int 109 }{ 110 { 111 name: "none", 112 ps: &struct { 113 Foo string 114 }{}, 115 want: nil, 116 }, 117 { 118 name: "one", 119 ps: &struct { 120 Foo string `name:"value"` 121 }{}, 122 want: [][]int{{0}}, 123 }, 124 { 125 name: "two", 126 ps: &struct { 127 Foo string `name:"value"` 128 Bar string `name:"value"` 129 }{}, 130 want: [][]int{{0}, {1}}, 131 }, 132 { 133 name: "some", 134 ps: &struct { 135 Foo string `name:"other"` 136 Bar string `name:"value"` 137 }{}, 138 want: [][]int{{1}}, 139 }, 140 { 141 name: "embedded", 142 ps: &struct { 143 Foo struct { 144 Bar string `name:"value"` 145 } 146 }{}, 147 want: [][]int{{0, 0}}, 148 }, 149 { 150 name: "embedded ptr", 151 ps: &struct { 152 Foo *struct { 153 Bar string `name:"value"` 154 } 155 }{}, 156 want: [][]int{{0, 0}}, 157 }, 158 { 159 name: "slice of struct", 160 ps: &struct { 161 Other int 162 Foo []struct { 163 Other int 164 Bar string `name:"value"` 165 } 166 }{}, 167 want: [][]int{{1, 1}}, 168 }, 169 { 170 name: "slice^2 of struct", 171 ps: &struct { 172 Other int 173 Foo []struct { 174 Other int 175 Bar []struct { 176 Other int 177 Baz string `name:"value"` 178 } 179 } 180 }{}, 181 want: [][]int{{1, 1, 1}}, 182 }, 183 { 184 name: "nil", 185 ps: (*struct { 186 Foo string `name:"value"` 187 })(nil), 188 want: [][]int{{0}}, 189 }, 190 } 191 for _, test := range tests { 192 t.Run(test.name, func(t *testing.T) { 193 if got := PropertyIndexesWithTag(test.ps, "name", "value"); !reflect.DeepEqual(got, test.want) { 194 t.Errorf("PropertyIndexesWithTag() = %v, want %v", got, test.want) 195 } 196 }) 197 } 198} 199