diff --git a/cmd/server/helpers_test.go b/cmd/server/helpers_test.go index 7ec5c703..b2bff47a 100644 --- a/cmd/server/helpers_test.go +++ b/cmd/server/helpers_test.go @@ -2,6 +2,8 @@ package main import ( "encoding/json" + "fmt" + "math/rand" "net/http" "net/http/httptest" "os" @@ -220,6 +222,44 @@ func TestSortedCopy(t *testing.T) { } } +func TestSortedCopyLarge(t *testing.T) { + // Regression: verify correct sort on larger input + rng := rand.New(rand.NewSource(42)) + n := 1000 + input := make([]float64, n) + for i := range input { + input[i] = rng.Float64() * 1000 + } + result := sortedCopy(input) + if len(result) != n { + t.Fatalf("expected %d elements, got %d", n, len(result)) + } + for i := 1; i < len(result); i++ { + if result[i] < result[i-1] { + t.Fatalf("not sorted at index %d: %v > %v", i, result[i-1], result[i]) + } + } + // Original unchanged + if input[0] == result[0] && input[1] == result[1] && input[2] == result[2] { + // Could be coincidence but very unlikely with random data + } +} + +func BenchmarkSortedCopy(b *testing.B) { + rng := rand.New(rand.NewSource(42)) + for _, size := range []int{256, 1000, 10000} { + data := make([]float64, size) + for i := range data { + data[i] = rng.Float64() * 1000 + } + b.Run(fmt.Sprintf("n=%d", size), func(b *testing.B) { + for i := 0; i < b.N; i++ { + sortedCopy(data) + } + }) + } +} + func TestLastN(t *testing.T) { arr := []map[string]interface{}{ {"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, diff --git a/cmd/server/routes.go b/cmd/server/routes.go index 87c9a5fd..98bef917 100644 --- a/cmd/server/routes.go +++ b/cmd/server/routes.go @@ -1958,13 +1958,7 @@ func percentile(sorted []float64, p float64) float64 { func sortedCopy(arr []float64) []float64 { cp := make([]float64, len(arr)) copy(cp, arr) - for i := 0; i < len(cp); i++ { - for j := i + 1; j < len(cp); j++ { - if cp[j] < cp[i] { - cp[i], cp[j] = cp[j], cp[i] - } - } - } + sort.Float64s(cp) return cp }