github.com/MetalBlockchain/metalgo@v1.11.9/utils/sampler/uniform_test.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package sampler
     5  
     6  import (
     7  	"fmt"
     8  	"math"
     9  	"slices"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  var (
    16  	uniformSamplers = []struct {
    17  		name    string
    18  		sampler Uniform
    19  	}{
    20  		{
    21  			name: "replacer",
    22  			sampler: &uniformReplacer{
    23  				rng: globalRNG,
    24  			},
    25  		},
    26  		{
    27  			name: "resampler",
    28  			sampler: &uniformResample{
    29  				rng: globalRNG,
    30  			},
    31  		},
    32  		{
    33  			name:    "best",
    34  			sampler: NewBestUniform(30),
    35  		},
    36  	}
    37  	uniformTests = []struct {
    38  		name string
    39  		test func(*testing.T, Uniform)
    40  	}{
    41  		{
    42  			name: "can sample large values",
    43  			test: UniformInitializeMaxUint64Test,
    44  		},
    45  		{
    46  			name: "out of range",
    47  			test: UniformOutOfRangeTest,
    48  		},
    49  		{
    50  			name: "empty",
    51  			test: UniformEmptyTest,
    52  		},
    53  		{
    54  			name: "singleton",
    55  			test: UniformSingletonTest,
    56  		},
    57  		{
    58  			name: "distribution",
    59  			test: UniformDistributionTest,
    60  		},
    61  		{
    62  			name: "over sample",
    63  			test: UniformOverSampleTest,
    64  		},
    65  		{
    66  			name: "lazily sample",
    67  			test: UniformLazilySample,
    68  		},
    69  	}
    70  )
    71  
    72  func TestAllUniform(t *testing.T) {
    73  	for _, s := range uniformSamplers {
    74  		for _, test := range uniformTests {
    75  			t.Run(fmt.Sprintf("sampler %s test %s", s.name, test.name), func(t *testing.T) {
    76  				test.test(t, s.sampler)
    77  			})
    78  		}
    79  	}
    80  }
    81  
    82  func UniformInitializeMaxUint64Test(t *testing.T, s Uniform) {
    83  	s.Initialize(math.MaxUint64)
    84  
    85  	for {
    86  		val, hasNext := s.Next()
    87  		require.True(t, hasNext)
    88  
    89  		if val > math.MaxInt64 {
    90  			break
    91  		}
    92  	}
    93  }
    94  
    95  func UniformOutOfRangeTest(t *testing.T, s Uniform) {
    96  	s.Initialize(0)
    97  
    98  	_, ok := s.Sample(1)
    99  	require.False(t, ok)
   100  }
   101  
   102  func UniformEmptyTest(t *testing.T, s Uniform) {
   103  	require := require.New(t)
   104  
   105  	s.Initialize(1)
   106  
   107  	val, ok := s.Sample(0)
   108  	require.True(ok)
   109  	require.Empty(val)
   110  }
   111  
   112  func UniformSingletonTest(t *testing.T, s Uniform) {
   113  	require := require.New(t)
   114  
   115  	s.Initialize(1)
   116  
   117  	val, ok := s.Sample(1)
   118  	require.True(ok)
   119  	require.Equal([]uint64{0}, val)
   120  }
   121  
   122  func UniformDistributionTest(t *testing.T, s Uniform) {
   123  	require := require.New(t)
   124  
   125  	s.Initialize(3)
   126  
   127  	val, ok := s.Sample(3)
   128  	require.True(ok)
   129  
   130  	slices.Sort(val)
   131  	require.Equal([]uint64{0, 1, 2}, val)
   132  }
   133  
   134  func UniformOverSampleTest(t *testing.T, s Uniform) {
   135  	s.Initialize(3)
   136  
   137  	_, ok := s.Sample(4)
   138  	require.False(t, ok)
   139  }
   140  
   141  func UniformLazilySample(t *testing.T, s Uniform) {
   142  	require := require.New(t)
   143  
   144  	s.Initialize(3)
   145  
   146  	for j := 0; j < 2; j++ {
   147  		sampled := map[uint64]bool{}
   148  		for i := 0; i < 3; i++ {
   149  			val, hasNext := s.Next()
   150  			require.True(hasNext)
   151  			require.False(sampled[val])
   152  
   153  			sampled[val] = true
   154  		}
   155  
   156  		_, hasNext := s.Next()
   157  		require.False(hasNext)
   158  
   159  		s.Reset()
   160  	}
   161  }