codeberg.org/gruf/go-mangler@v1.3.0/mangle_test.go (about) 1 package mangler_test 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/json" 7 "fmt" 8 "net/url" 9 "reflect" 10 "strconv" 11 "testing" 12 "time" 13 14 "codeberg.org/gruf/go-loosy" 15 "codeberg.org/gruf/go-mangler" 16 17 "github.com/cnf/structhash" 18 "github.com/fxamacker/cbor" 19 "github.com/mitchellh/hashstructure/v2" 20 ) 21 22 type unsignedint uint 23 24 type byteslice []byte 25 26 type mangled struct{} 27 28 func (m *mangled) Mangle(buf []byte) []byte { 29 return buf 30 } 31 32 type mangledint int 33 34 func (i mangledint) Mangle(buf []byte) []byte { 35 return strconv.AppendInt(buf, int64(i), 10) 36 } 37 38 var vars = []any{ 39 "hello world", 40 []byte("hello world"), 41 []rune("hello world"), 42 byteslice("hello world"), 43 []int64{0, 1, 2, 3, 4, 5}, 44 []uint32{0, 1, 2, 3, 4, 5}, 45 []uintptr{0, 1, 2, 3, 4, 5}, 46 []*uint{nil, nil, nil, nil, nil, nil}, 47 []**uint{nil, nil, nil, nil, nil, nil}, 48 [6]int64{0, 1, 2, 3, 4, 5}, 49 [6]uint32{0, 1, 2, 3, 4, 5}, 50 [6]uintptr{0, 1, 2, 3, 4, 5}, 51 [6]byte{'h', 'e', 'l', 'l', 'o', '!'}, 52 [6]*uint{nil, nil, nil, nil, nil, nil}, 53 [6]**uint{nil, nil, nil, nil, nil, nil}, 54 int(1), 55 int8(2), 56 int16(3), 57 int32(4), 58 int64(5), 59 uint(6), 60 uint8(7), 61 uint16(8), 62 uint32(9), 63 uint64(10), 64 uintptr(11), 65 float32(12), 66 float64(13), 67 complex64(14), 68 complex128(15), 69 unsignedint(16), 70 time.Now(), 71 time.Second, 72 map[string]string{"hello": "world", "key": "value"}, 73 map[int64]float32{0: 0, 1: 1, 2: 2}, 74 map[float64]int32{0: 0, 1: 1, 2: 2}, 75 map[uintptr]unsignedint{0: 0, 1: 1, 2: 2}, 76 map[string]byteslice{"hello": byteslice("world")}, 77 map[*string]*string{nil: nil}, 78 map[**string]**string{nil: nil}, 79 func() url.URL { u, _ := url.Parse("https://google.com/"); return *u }(), 80 url.Values{"hello": []string{"worlds"}}, 81 ptr_to("hello world"), 82 ptr_to([]byte("hello world")), 83 ptr_to([]rune("hello world")), 84 ptr_to(byteslice("hello world")), 85 ptr_to([]int64{0, 1, 2, 3, 4, 5}), 86 ptr_to([]uint32{0, 1, 2, 3, 4, 5}), 87 ptr_to([]uintptr{0, 1, 2, 3, 4, 5}), 88 ptr_to([]*uint{nil, nil, nil, nil, nil, nil}), 89 ptr_to([]**uint{nil, nil, nil, nil, nil, nil}), 90 ptr_to([6]int64{0, 1, 2, 3, 4, 5}), 91 ptr_to([6]uint32{0, 1, 2, 3, 4, 5}), 92 ptr_to([6]uintptr{0, 1, 2, 3, 4, 5}), 93 ptr_to([6]byte{'h', 'e', 'l', 'l', 'o', '!'}), 94 ptr_to([6]*uint{nil, nil, nil, nil, nil, nil}), 95 ptr_to([6]**uint{nil, nil, nil, nil, nil, nil}), 96 ptr_to(int(1)), 97 ptr_to(int8(2)), 98 ptr_to(int16(3)), 99 ptr_to(int32(4)), 100 ptr_to(int64(5)), 101 ptr_to(uint(6)), 102 ptr_to(uint8(7)), 103 ptr_to(uint16(8)), 104 ptr_to(uint32(9)), 105 ptr_to(uint64(10)), 106 ptr_to(uintptr(11)), 107 ptr_to(float32(12)), 108 ptr_to(float64(13)), 109 ptr_to(complex64(14)), 110 ptr_to(complex128(15)), 111 ptr_to(unsignedint(16)), 112 ptr_to(time.Now()), 113 ptr_to(time.Second), 114 ptr_to(mangled{}), 115 ptr_to(map[*string]*string{nil: nil}), 116 ptr_to(map[**string]**string{nil: nil}), 117 ptr_to(url.Values{"hello": []string{"worlds"}}), 118 func() *url.URL { u, _ := url.Parse("https://google.com/"); return u }(), 119 120 // All of the below cause "binary" benchmark to fail: 121 // (*string)(nil), 122 // (*[]byte)(nil), 123 // (*[]rune)(nil), 124 // (*byteslice)(nil), 125 // (*[]int64)(nil), 126 // (*[]uint32)(nil), 127 // (*[]uintptr)(nil), 128 // (*int)(nil), 129 // (*int8)(nil), 130 // (*int16)(nil), 131 // (*int32)(nil), 132 // (*int64)(nil), 133 // (*uint)(nil), 134 // (*uint8)(nil), 135 // (*uint16)(nil), 136 // (*uint32)(nil), 137 // (*uint64)(nil), 138 // (*uintptr)(nil), 139 // (*float32)(nil), 140 // (*float64)(nil), 141 // (*complex64)(nil), 142 // (*complex128)(nil), 143 // (*unsignedint)(nil), 144 // (*time.Time)(nil), 145 // (*time.Duration)(nil), 146 // (*mangled)(nil), 147 // (*map[string]string)(nil), 148 } 149 150 func ptr_to[T any](t T) *T { 151 return &t 152 } 153 154 func TestMangleIntUniqueness(t *testing.T) { 155 test := map[string]bool{} 156 for i := uint(0); i < 1e6; i++ { 157 key := mangler.String(i) 158 if test[key] { 159 t.Fatal("uniqueness fail") 160 } 161 test[key] = true 162 } 163 } 164 165 func TestMangleInt8Uniqueness(t *testing.T) { 166 test := map[string]bool{} 167 for i := uint8(0); i < 255; i++ { 168 key := mangler.String(i) 169 if test[key] { 170 t.Fatal("uniqueness fail") 171 } 172 test[key] = true 173 } 174 } 175 176 func TestMangleInt16Uniqueness(t *testing.T) { 177 test := map[string]bool{} 178 for i := uint16(0); i < ^uint16(0); i++ { 179 key := mangler.String(i) 180 if test[key] { 181 t.Fatal("uniqueness fail") 182 } 183 test[key] = true 184 } 185 } 186 187 func TestMangleInt32Uniqueness(t *testing.T) { 188 test := map[string]bool{} 189 for i := uint32(0); i < 1e6; i++ { 190 key := mangler.String(i) 191 if test[key] { 192 t.Fatal("uniqueness fail") 193 } 194 test[key] = true 195 } 196 } 197 198 func TestMangleInt64Uniqueness(t *testing.T) { 199 test := map[string]bool{} 200 for i := uint64(0); i < 1e6; i++ { 201 key := mangler.String(i) 202 if test[key] { 203 t.Fatal("uniqueness fail") 204 } 205 test[key] = true 206 } 207 } 208 209 func TestMangleFloat32Uniqueness(t *testing.T) { 210 test := map[string]bool{} 211 for i := float32(0); i < 1e6; i++ { 212 key := mangler.String(i) 213 if test[key] { 214 t.Fatal("uniqueness fail") 215 } 216 test[key] = true 217 } 218 } 219 220 func TestMangleFloat64Uniqueness(t *testing.T) { 221 test := map[string]bool{} 222 for i := float64(0); i < 1e6; i++ { 223 key := mangler.String(i) 224 if test[key] { 225 t.Fatal("uniqueness fail") 226 } 227 test[key] = true 228 } 229 } 230 231 func TestMangleTimeUniqueness(t *testing.T) { 232 test := map[string]bool{} 233 var tm time.Time 234 for i := 0; i < 1e6; i++ { 235 key := mangler.String(tm) 236 if test[key] { 237 t.Fatal("uniqueness fail") 238 } 239 test[key] = true 240 tm = tm.Add(time.Second) 241 } 242 } 243 244 func TestMangleDurationUniqueness(t *testing.T) { 245 test := map[string]bool{} 246 var d time.Duration 247 for i := 0; i < 1e6; i++ { 248 key := mangler.String(d) 249 if test[key] { 250 t.Fatal("uniqueness fail") 251 } 252 test[key] = true 253 d += time.Second 254 } 255 } 256 257 func TestMangleMangledUniqueness(t *testing.T) { 258 test := map[string]bool{} 259 for i := mangledint(0); i < 1e6; i++ { 260 key := mangler.String(i) 261 if test[key] { 262 t.Fatal("uniqueness fail") 263 } 264 test[key] = true 265 } 266 } 267 268 func BenchmarkMangle(b *testing.B) { 269 b.ResetTimer() 270 b.RunParallel(func(pb *testing.PB) { 271 var b []byte 272 273 for pb.Next() { 274 for _, v := range vars { 275 b = mangler.Append(b, v) 276 b = b[:0] 277 } 278 } 279 280 b = b[:0] 281 }) 282 } 283 284 func BenchmarkMangleKnown(b *testing.B) { 285 var manglers []mangler.Mangler 286 287 for _, v := range vars { 288 t := reflect.TypeOf(v) 289 m := mangler.Get(t) 290 manglers = append(manglers, m) 291 } 292 293 b.ResetTimer() 294 b.RunParallel(func(pb *testing.PB) { 295 var b []byte 296 297 for pb.Next() { 298 for i, v := range vars { 299 b = manglers[i](b, v) 300 b = b[:0] 301 } 302 } 303 304 b = b[:0] 305 }) 306 } 307 308 func BenchmarkJSON(b *testing.B) { 309 b.ResetTimer() 310 b.RunParallel(func(pb *testing.PB) { 311 for pb.Next() { 312 var b []byte 313 314 for _, v := range vars { 315 b, _ = json.Marshal(v) 316 b = b[:0] 317 } 318 319 b = b[:0] 320 } 321 }) 322 } 323 324 func BenchmarkLoosy(b *testing.B) { 325 b.ResetTimer() 326 b.RunParallel(func(pb *testing.PB) { 327 var b bytes.Buffer 328 329 for pb.Next() { 330 for _, v := range vars { 331 loosy.MarshalWrite(&b, v) 332 b.Reset() 333 } 334 } 335 336 b.Reset() 337 }) 338 } 339 340 func BenchmarkBinary(b *testing.B) { 341 b.ResetTimer() 342 b.RunParallel(func(pb *testing.PB) { 343 var b bytes.Buffer 344 345 for pb.Next() { 346 for _, v := range vars { 347 binary.Write(&b, binary.LittleEndian, v) 348 b.Reset() 349 } 350 } 351 352 b.Reset() 353 }) 354 } 355 356 func BenchmarkFmt(b *testing.B) { 357 b.ResetTimer() 358 b.RunParallel(func(pb *testing.PB) { 359 var b []byte 360 361 for pb.Next() { 362 for _, v := range vars { 363 b = fmt.Append(b, v) 364 b = b[:0] 365 } 366 } 367 368 b = b[:0] 369 }) 370 } 371 372 func BenchmarkFxmackerCbor(b *testing.B) { 373 b.ResetTimer() 374 b.RunParallel(func(pb *testing.PB) { 375 opts := cbor.CanonicalEncOptions() 376 377 for pb.Next() { 378 var b []byte 379 380 for _, v := range vars { 381 b, _ = cbor.Marshal(v, opts) 382 } 383 384 b = b[:0] 385 } 386 }) 387 } 388 389 func BenchmarkMitchellhHashStructure(b *testing.B) { 390 b.ResetTimer() 391 b.RunParallel(func(pb *testing.PB) { 392 for pb.Next() { 393 var b []byte 394 395 for _, v := range vars { 396 u, _ := hashstructure.Hash(v, hashstructure.FormatV2, nil) 397 b = binary.LittleEndian.AppendUint64(b, u) 398 b = b[:0] 399 } 400 401 b = b[:0] 402 } 403 }) 404 } 405 406 func BenchmarkCnfStructhash(b *testing.B) { 407 b.ResetTimer() 408 b.RunParallel(func(pb *testing.PB) { 409 for pb.Next() { 410 var b []byte 411 412 for _, v := range vars { 413 b = structhash.Dump(v, 0) 414 b = b[:0] 415 } 416 417 b = b[:0] 418 } 419 }) 420 }