go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/proto/reflectutil/sorted_range_test.go (about) 1 // Copyright 2022 The LUCI Authors. 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 15 package reflectutil 16 17 import ( 18 "sort" 19 "strconv" 20 "testing" 21 22 . "github.com/smartystreets/goconvey/convey" 23 "google.golang.org/protobuf/reflect/protoreflect" 24 ) 25 26 func TestMapRangeSorted(t *testing.T) { 27 t.Parallel() 28 29 Convey(`MapRangeSorted`, t, func() { 30 Convey(`empty`, func() { 31 msg := &TestMapMessage{} 32 refl := msg.ProtoReflect() 33 getField := func() protoreflect.Map { return refl.Get(refl.Descriptor().Fields().ByName("string_map")).Map() } 34 MapRangeSorted(getField(), protoreflect.StringKind, func(protoreflect.MapKey, protoreflect.Value) bool { 35 panic("callback called for empty map?") 36 }) 37 }) 38 39 Convey(`bool`, func() { 40 type item struct { 41 k bool 42 v string 43 } 44 msg := &TestMapMessage{} 45 refl := msg.ProtoReflect() 46 getField := func() protoreflect.Map { return refl.Get(refl.Descriptor().Fields().ByName("bool_map")).Map() } 47 48 Convey(`true`, func() { 49 msg.BoolMap = map[bool]string{true: "hey"} 50 results := []item{} 51 MapRangeSorted(getField(), protoreflect.BoolKind, func(k protoreflect.MapKey, v protoreflect.Value) bool { 52 results = append(results, item{k.Bool(), v.String()}) 53 return true 54 }) 55 So(results, ShouldResemble, []item{{true, "hey"}}) 56 }) 57 Convey(`false`, func() { 58 msg.BoolMap = map[bool]string{false: "hey"} 59 results := []item{} 60 MapRangeSorted(getField(), protoreflect.BoolKind, func(k protoreflect.MapKey, v protoreflect.Value) bool { 61 results = append(results, item{k.Bool(), v.String()}) 62 return true 63 }) 64 So(results, ShouldResemble, []item{{false, "hey"}}) 65 }) 66 Convey(`both`, func() { 67 msg.BoolMap = map[bool]string{false: "hey", true: "norp"} 68 results := []item{} 69 MapRangeSorted(getField(), protoreflect.BoolKind, func(k protoreflect.MapKey, v protoreflect.Value) bool { 70 results = append(results, item{k.Bool(), v.String()}) 71 return true 72 }) 73 So(results, ShouldResemble, []item{{false, "hey"}, {true, "norp"}}) 74 }) 75 }) 76 77 Convey(`int`, func() { 78 type item struct { 79 k int64 80 v string 81 } 82 msg := &TestMapMessage{} 83 refl := msg.ProtoReflect() 84 get32Field := func() protoreflect.Map { return refl.Get(refl.Descriptor().Fields().ByName("int32_map")).Map() } 85 get64Field := func() protoreflect.Map { return refl.Get(refl.Descriptor().Fields().ByName("int64_map")).Map() } 86 87 Convey(`int32`, func() { 88 msg.Int32Map = map[int32]string{} 89 expect := []item{} 90 for i := int64(0); i < 100; i++ { 91 entry := item{i, strconv.FormatInt(i, 10)} 92 msg.Int32Map[int32(i)] = entry.v 93 expect = append(expect, entry) 94 } 95 results := []item{} 96 MapRangeSorted(get32Field(), protoreflect.Int32Kind, func(k protoreflect.MapKey, v protoreflect.Value) bool { 97 results = append(results, item{k.Int(), v.String()}) 98 return true 99 }) 100 So(results, ShouldResemble, expect) 101 }) 102 103 Convey(`int64`, func() { 104 msg.Int64Map = map[int64]string{} 105 expect := []item{} 106 for i := int64(0); i < 100; i++ { 107 entry := item{i, strconv.FormatInt(i, 10)} 108 msg.Int64Map[i] = entry.v 109 expect = append(expect, entry) 110 } 111 results := []item{} 112 MapRangeSorted(get64Field(), protoreflect.Int64Kind, func(k protoreflect.MapKey, v protoreflect.Value) bool { 113 results = append(results, item{k.Int(), v.String()}) 114 return true 115 }) 116 So(results, ShouldResemble, expect) 117 }) 118 119 }) 120 121 Convey(`uint`, func() { 122 type item struct { 123 k uint64 124 v string 125 } 126 msg := &TestMapMessage{} 127 refl := msg.ProtoReflect() 128 get32Field := func() protoreflect.Map { return refl.Get(refl.Descriptor().Fields().ByName("uint32_map")).Map() } 129 get64Field := func() protoreflect.Map { return refl.Get(refl.Descriptor().Fields().ByName("uint64_map")).Map() } 130 131 Convey(`uint32`, func() { 132 msg.Uint32Map = map[uint32]string{} 133 expect := []item{} 134 for i := uint64(0); i < 100; i++ { 135 entry := item{i, strconv.FormatUint(i, 10)} 136 msg.Uint32Map[uint32(i)] = entry.v 137 expect = append(expect, entry) 138 } 139 results := []item{} 140 MapRangeSorted(get32Field(), protoreflect.Uint32Kind, func(k protoreflect.MapKey, v protoreflect.Value) bool { 141 results = append(results, item{k.Uint(), v.String()}) 142 return true 143 }) 144 So(results, ShouldResemble, expect) 145 }) 146 147 Convey(`uint64`, func() { 148 msg.Uint64Map = map[uint64]string{} 149 expect := []item{} 150 for i := uint64(0); i < 100; i++ { 151 entry := item{i, strconv.FormatUint(i, 10)} 152 msg.Uint64Map[i] = entry.v 153 expect = append(expect, entry) 154 } 155 results := []item{} 156 MapRangeSorted(get64Field(), protoreflect.Uint64Kind, func(k protoreflect.MapKey, v protoreflect.Value) bool { 157 results = append(results, item{k.Uint(), v.String()}) 158 return true 159 }) 160 So(results, ShouldResemble, expect) 161 }) 162 }) 163 164 Convey(`string`, func() { 165 msg := &TestMapMessage{} 166 refl := msg.ProtoReflect() 167 getField := func() protoreflect.Map { return refl.Get(refl.Descriptor().Fields().ByName("string_map")).Map() } 168 169 msg.StringMap = map[string]string{} 170 expect := []string{} 171 for i := uint64(0); i < 100; i++ { 172 entry := strconv.FormatUint(i, 10) 173 msg.StringMap[entry] = entry 174 expect = append(expect, entry) 175 } 176 // expect is sorted alphanumerically, not numerically 177 sort.Strings(expect) 178 179 results := []string{} 180 MapRangeSorted(getField(), protoreflect.StringKind, func(k protoreflect.MapKey, v protoreflect.Value) bool { 181 if k.String() != v.String() { 182 panic("mismatched key/value") 183 } 184 results = append(results, v.String()) 185 return true 186 }) 187 So(results, ShouldResemble, expect) 188 }) 189 }) 190 }