| 
									
										
										
										
											2025-05-28 03:49:13 +03:00
										 |  |  | package rand
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							|  |  |  | 	"sync"
 | 
					
						
							|  |  |  | 	"testing"
 | 
					
						
							|  |  |  | 	"time"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestNew(t *testing.T) {
 | 
					
						
							|  |  |  | 	tests := []struct {
 | 
					
						
							|  |  |  | 		name string
 | 
					
						
							|  |  |  | 		seed int64
 | 
					
						
							|  |  |  | 	}{
 | 
					
						
							|  |  |  | 		{
 | 
					
						
							|  |  |  | 			name: "positive seed",
 | 
					
						
							|  |  |  | 			seed: 12345,
 | 
					
						
							|  |  |  | 		},
 | 
					
						
							|  |  |  | 		{
 | 
					
						
							|  |  |  | 			name: "zero seed",
 | 
					
						
							|  |  |  | 			seed: 0,
 | 
					
						
							|  |  |  | 		},
 | 
					
						
							|  |  |  | 		{
 | 
					
						
							|  |  |  | 			name: "negative seed",
 | 
					
						
							|  |  |  | 			seed: -12345,
 | 
					
						
							|  |  |  | 		},
 | 
					
						
							|  |  |  | 		{
 | 
					
						
							|  |  |  | 			name: "current time seed",
 | 
					
						
							|  |  |  | 			seed: time.Now().UnixNano(),
 | 
					
						
							|  |  |  | 		},
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests {
 | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) {
 | 
					
						
							|  |  |  | 			r := New(test.seed)
 | 
					
						
							|  |  |  | 			if r.r == nil {
 | 
					
						
							|  |  |  | 				t.Error("internal rand.Rand is nil")
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		})
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestIntDeterministic(t *testing.T) {
 | 
					
						
							|  |  |  | 	seed := int64(42)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create two generators with the same seed
 | 
					
						
							|  |  |  | 	r1 := New(seed)
 | 
					
						
							|  |  |  | 	r2 := New(seed)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// They should produce the same sequence
 | 
					
						
							| 
									
										
										
										
											2025-05-29 03:50:55 +03:00
										 |  |  | 	for i := range 10 {
 | 
					
						
							| 
									
										
										
										
											2025-05-28 03:49:13 +03:00
										 |  |  | 		val1 := r1.Int()
 | 
					
						
							|  |  |  | 		val2 := r2.Int()
 | 
					
						
							|  |  |  | 		if val1 != val2 {
 | 
					
						
							|  |  |  | 			t.Errorf("generators with same seed produced different values at iteration %d: %d != %d", i, val1, val2)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestPerm(t *testing.T) {
 | 
					
						
							|  |  |  | 	r := New(12345)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tests := []struct {
 | 
					
						
							|  |  |  | 		name string
 | 
					
						
							|  |  |  | 		n    int
 | 
					
						
							|  |  |  | 	}{
 | 
					
						
							|  |  |  | 		{
 | 
					
						
							|  |  |  | 			name: "empty permutation",
 | 
					
						
							|  |  |  | 			n:    0,
 | 
					
						
							|  |  |  | 		},
 | 
					
						
							|  |  |  | 		{
 | 
					
						
							|  |  |  | 			name: "single element",
 | 
					
						
							|  |  |  | 			n:    1,
 | 
					
						
							|  |  |  | 		},
 | 
					
						
							|  |  |  | 		{
 | 
					
						
							|  |  |  | 			name: "small permutation",
 | 
					
						
							|  |  |  | 			n:    5,
 | 
					
						
							|  |  |  | 		},
 | 
					
						
							|  |  |  | 		{
 | 
					
						
							|  |  |  | 			name: "larger permutation",
 | 
					
						
							|  |  |  | 			n:    20,
 | 
					
						
							|  |  |  | 		},
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, test := range tests {
 | 
					
						
							|  |  |  | 		t.Run(test.name, func(t *testing.T) {
 | 
					
						
							|  |  |  | 			perm := r.Perm(test.n)
 | 
					
						
							|  |  |  | 			if len(perm) != test.n {
 | 
					
						
							|  |  |  | 				t.Errorf("Perm(%d) returned slice of length %d", test.n, len(perm))
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		})
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestPermDeterministic(t *testing.T) {
 | 
					
						
							|  |  |  | 	seed := int64(42)
 | 
					
						
							|  |  |  | 	n := 10
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create two generators with the same seed
 | 
					
						
							|  |  |  | 	r1 := New(seed)
 | 
					
						
							|  |  |  | 	r2 := New(seed)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	perm1 := r1.Perm(n)
 | 
					
						
							|  |  |  | 	perm2 := r2.Perm(n)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// They should produce the same permutation
 | 
					
						
							|  |  |  | 	if len(perm1) != len(perm2) {
 | 
					
						
							|  |  |  | 		t.Errorf("permutations have different lengths: %d != %d", len(perm1), len(perm2))
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := 0; i < len(perm1) && i < len(perm2); i++ {
 | 
					
						
							|  |  |  | 		if perm1[i] != perm2[i] {
 | 
					
						
							|  |  |  | 			t.Errorf("permutations differ at index %d: %d != %d", i, perm1[i], perm2[i])
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestConcurrentAccess(t *testing.T) {
 | 
					
						
							|  |  |  | 	r := New(12345)
 | 
					
						
							|  |  |  | 	numGoroutines := 10
 | 
					
						
							|  |  |  | 	numOperations := 100
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var wg sync.WaitGroup
 | 
					
						
							|  |  |  | 	errors := make(chan error, numGoroutines*numOperations)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Test concurrent Int() calls
 | 
					
						
							| 
									
										
										
										
											2025-05-29 03:50:55 +03:00
										 |  |  | 	for range numGoroutines {
 | 
					
						
							| 
									
										
										
										
											2025-05-28 03:49:13 +03:00
										 |  |  | 		wg.Add(1)
 | 
					
						
							|  |  |  | 		go func() {
 | 
					
						
							|  |  |  | 			defer wg.Done()
 | 
					
						
							| 
									
										
										
										
											2025-05-29 03:50:55 +03:00
										 |  |  | 			for range numOperations {
 | 
					
						
							| 
									
										
										
										
											2025-05-28 03:49:13 +03:00
										 |  |  | 				val := r.Int()
 | 
					
						
							|  |  |  | 				if val < 0 {
 | 
					
						
							|  |  |  | 					errors <- nil
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}()
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Test concurrent Perm() calls
 | 
					
						
							| 
									
										
										
										
											2025-05-29 03:50:55 +03:00
										 |  |  | 	for range numGoroutines {
 | 
					
						
							| 
									
										
										
										
											2025-05-28 03:49:13 +03:00
										 |  |  | 		wg.Add(1)
 | 
					
						
							|  |  |  | 		go func() {
 | 
					
						
							|  |  |  | 			defer wg.Done()
 | 
					
						
							| 
									
										
										
										
											2025-05-29 03:50:55 +03:00
										 |  |  | 			for range numOperations {
 | 
					
						
							| 
									
										
										
										
											2025-05-28 03:49:13 +03:00
										 |  |  | 				perm := r.Perm(5)
 | 
					
						
							|  |  |  | 				if len(perm) != 5 {
 | 
					
						
							|  |  |  | 					errors <- nil
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}()
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wg.Wait()
 | 
					
						
							|  |  |  | 	close(errors)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	errorCount := 0
 | 
					
						
							|  |  |  | 	for range errors {
 | 
					
						
							|  |  |  | 		errorCount++
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if errorCount > 0 {
 | 
					
						
							|  |  |  | 		t.Errorf("concurrent access resulted in %d errors", errorCount)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestConcurrentMixedOperations(t *testing.T) {
 | 
					
						
							|  |  |  | 	r := New(time.Now().UnixNano())
 | 
					
						
							|  |  |  | 	numGoroutines := 5
 | 
					
						
							|  |  |  | 	numOperations := 50
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var wg sync.WaitGroup
 | 
					
						
							|  |  |  | 	errors := make(chan error, numGoroutines*numOperations)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Mix of Int() and Perm() operations running concurrently
 | 
					
						
							| 
									
										
										
										
											2025-05-29 03:50:55 +03:00
										 |  |  | 	for i := range numGoroutines {
 | 
					
						
							| 
									
										
										
										
											2025-05-28 03:49:13 +03:00
										 |  |  | 		wg.Add(1)
 | 
					
						
							|  |  |  | 		go func(id int) {
 | 
					
						
							|  |  |  | 			defer wg.Done()
 | 
					
						
							| 
									
										
										
										
											2025-05-29 03:50:55 +03:00
										 |  |  | 			for j := range numOperations {
 | 
					
						
							| 
									
										
										
										
											2025-05-28 03:49:13 +03:00
										 |  |  | 				if j%2 == 0 {
 | 
					
						
							|  |  |  | 					val := r.Int()
 | 
					
						
							|  |  |  | 					if val < 0 {
 | 
					
						
							|  |  |  | 						errors <- nil
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 				} else {
 | 
					
						
							|  |  |  | 					perm := r.Perm(3)
 | 
					
						
							|  |  |  | 					if len(perm) != 3 {
 | 
					
						
							|  |  |  | 						errors <- nil
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}(i)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wg.Wait()
 | 
					
						
							|  |  |  | 	close(errors)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	errorCount := 0
 | 
					
						
							|  |  |  | 	for range errors {
 | 
					
						
							|  |  |  | 		errorCount++
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if errorCount > 0 {
 | 
					
						
							|  |  |  | 		t.Errorf("concurrent mixed operations resulted in %d errors", errorCount)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 |