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  }