a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
261 lines
6.8 KiB
Go
261 lines
6.8 KiB
Go
package main
|
||
|
||
import (
|
||
"encoding/json"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
func TestResolveRepoSpec_PresetSlug(t *testing.T) {
|
||
s, err := resolveRepoSpec("gin")
|
||
if err != nil {
|
||
t.Fatalf("resolveRepoSpec(gin): %v", err)
|
||
}
|
||
if s.Slug != "gin" || !strings.Contains(s.URL, "gin-gonic/gin") {
|
||
t.Errorf("gin preset = %+v, want slug=gin URL containing gin-gonic/gin", s)
|
||
}
|
||
}
|
||
|
||
func TestResolveRepoSpec_OwnerRepoShorthand(t *testing.T) {
|
||
s, err := resolveRepoSpec("foo/bar")
|
||
if err != nil {
|
||
t.Fatalf("resolveRepoSpec(foo/bar): %v", err)
|
||
}
|
||
if s.Slug != "bar" || s.URL != "https://github.com/foo/bar.git" {
|
||
t.Errorf("owner/repo shorthand = %+v, want github URL", s)
|
||
}
|
||
}
|
||
|
||
func TestResolveRepoSpec_HTTPSPath(t *testing.T) {
|
||
s, err := resolveRepoSpec("https://example.com/path/to/myrepo.git")
|
||
if err != nil {
|
||
t.Fatalf("resolveRepoSpec(URL): %v", err)
|
||
}
|
||
if s.URL != "https://example.com/path/to/myrepo.git" || s.Slug != "myrepo" {
|
||
t.Errorf("URL spec = %+v, want slug=myrepo", s)
|
||
}
|
||
}
|
||
|
||
func TestResolveRepoSpec_LocalPath(t *testing.T) {
|
||
dir := t.TempDir()
|
||
s, err := resolveRepoSpec("local:" + dir)
|
||
if err != nil {
|
||
t.Fatalf("resolveRepoSpec(local:): %v", err)
|
||
}
|
||
if !s.Local || s.Path != dir {
|
||
t.Errorf("local spec = %+v, want Local=true Path=%s", s, dir)
|
||
}
|
||
}
|
||
|
||
func TestResolveRepoSpec_Empty(t *testing.T) {
|
||
if _, err := resolveRepoSpec(""); err == nil {
|
||
t.Error("expected error for empty repo token")
|
||
}
|
||
}
|
||
|
||
func TestResolveRepoSpec_UnknownSlug(t *testing.T) {
|
||
if _, err := resolveRepoSpec("nonexistent"); err == nil {
|
||
t.Error("expected error for unknown bare slug")
|
||
}
|
||
}
|
||
|
||
func TestLoadQueries(t *testing.T) {
|
||
dir := t.TempDir()
|
||
path := filepath.Join(dir, "queries.json")
|
||
body := `{"queries": ["FooBar", "validate_token", "auth middleware"]}`
|
||
if err := os.WriteFile(path, []byte(body), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
got, err := loadQueries(path)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if len(got) != 3 || got[0] != "FooBar" {
|
||
t.Errorf("got %+v, want 3 queries starting with FooBar", got)
|
||
}
|
||
}
|
||
|
||
func TestLoadQueries_MissingFile(t *testing.T) {
|
||
if _, err := loadQueries(filepath.Join(t.TempDir(), "missing.json")); err == nil {
|
||
t.Error("expected error for missing file")
|
||
}
|
||
}
|
||
|
||
func TestLoadQueries_MalformedJSON(t *testing.T) {
|
||
dir := t.TempDir()
|
||
path := filepath.Join(dir, "broken.json")
|
||
if err := os.WriteFile(path, []byte("{not json"), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if _, err := loadQueries(path); err == nil {
|
||
t.Error("expected error for malformed JSON")
|
||
}
|
||
}
|
||
|
||
func TestPctMs(t *testing.T) {
|
||
cases := []struct {
|
||
name string
|
||
in []time.Duration
|
||
pct int
|
||
want float64
|
||
}{
|
||
{"empty", nil, 50, 0},
|
||
{"single", []time.Duration{2 * time.Millisecond}, 50, 2.0},
|
||
{"p50 of 5", []time.Duration{
|
||
1 * time.Millisecond, 2 * time.Millisecond, 3 * time.Millisecond,
|
||
4 * time.Millisecond, 5 * time.Millisecond,
|
||
}, 50, 3.0},
|
||
// Nearest-rank percentile: idx = (pct × n) / 100. For
|
||
// durations(20)=[1..20]ms, p95 = sorted[19] = 20ms.
|
||
{"p95 of 20", durations(20), 95, 20.0},
|
||
{"p99 of 100", durations(100), 99, 100.0},
|
||
}
|
||
for _, c := range cases {
|
||
got := pctMs(c.in, c.pct)
|
||
if got != c.want {
|
||
t.Errorf("%s: pctMs = %.2f, want %.2f", c.name, got, c.want)
|
||
}
|
||
}
|
||
}
|
||
|
||
func durations(n int) []time.Duration {
|
||
out := make([]time.Duration, n)
|
||
for i := range out {
|
||
out[i] = time.Duration(i+1) * time.Millisecond
|
||
}
|
||
return out
|
||
}
|
||
|
||
func TestRenderMarkdown_PopulatesTable(t *testing.T) {
|
||
rows := []repoRow{
|
||
{Slug: "gin", LoC: 1000, Files: 50, Nodes: 800, Edges: 1200,
|
||
ColdIndexMs: 250.0, SearchP95Ms: 0.5, ImpactP95Ms: 0.3, ImpactP99Ms: 0.7,
|
||
IncrementalMs: 30, DBBytes: 250_000},
|
||
{Slug: "nestjs", LoC: 5000, Files: 200, Nodes: 4500, Edges: 7000,
|
||
ColdIndexMs: 1200, SearchP95Ms: 2.0, ImpactP95Ms: 1.5, ImpactP99Ms: 3.1,
|
||
IncrementalMs: 60, DBBytes: 1_500_000, BudgetViolations: 1},
|
||
{Slug: "broken", Error: "clone failed"},
|
||
}
|
||
md := renderMarkdown(rows)
|
||
for _, want := range []string{
|
||
"# Reference-repo perf benchmark",
|
||
"| repo | LoC |",
|
||
"| gin |",
|
||
"| nestjs |",
|
||
"⚠ 1",
|
||
"✗ (clone failed)",
|
||
"**Summary:**",
|
||
"2/3 repos succeeded",
|
||
} {
|
||
if !strings.Contains(md, want) {
|
||
t.Errorf("rendered markdown missing %q\n----\n%s", want, md)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestRenderCSV_HasHeaderAndRows(t *testing.T) {
|
||
rows := []repoRow{
|
||
{Slug: "gin", LoC: 1000, Files: 50, ColdIndexMs: 100, SearchP95Ms: 0.5, ImpactP95Ms: 0.2},
|
||
}
|
||
csvOut := renderCSV(rows)
|
||
if !strings.HasPrefix(csvOut, "slug,path,loc,files,nodes,edges,") {
|
||
t.Errorf("CSV header missing or wrong:\n%s", csvOut)
|
||
}
|
||
if !strings.Contains(csvOut, "gin,") {
|
||
t.Errorf("CSV body missing gin row:\n%s", csvOut)
|
||
}
|
||
}
|
||
|
||
func TestMustMarshalJSON_RoundTrip(t *testing.T) {
|
||
rows := []repoRow{{Slug: "gin", LoC: 100, Files: 5, ImpactP95Ms: 0.5}}
|
||
raw := mustMarshalJSON(rows)
|
||
var got []repoRow
|
||
if err := json.Unmarshal(raw, &got); err != nil {
|
||
t.Fatalf("round-trip failed: %v", err)
|
||
}
|
||
if len(got) != 1 || got[0].Slug != "gin" || got[0].ImpactP95Ms != 0.5 {
|
||
t.Errorf("round-trip lost data: %+v", got)
|
||
}
|
||
}
|
||
|
||
func TestFmtMs_Buckets(t *testing.T) {
|
||
cases := map[float64]string{
|
||
0: "—",
|
||
0.25: "0.25ms",
|
||
3.7: "3.7ms",
|
||
1500: "1.50s",
|
||
60_000: "60.00s",
|
||
}
|
||
for in, want := range cases {
|
||
if got := fmtMs(in); got != want {
|
||
t.Errorf("fmtMs(%v) = %q, want %q", in, got, want)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestFmtBytes_Buckets(t *testing.T) {
|
||
cases := map[int64]string{
|
||
0: "—",
|
||
-1: "—",
|
||
512: "512B",
|
||
2048: "2.0KB",
|
||
3 * 1024 * 1024: "3.0MB",
|
||
2 * 1024 * 1024 * 1024: "2.00GB",
|
||
}
|
||
for in, want := range cases {
|
||
if got := fmtBytes(in); got != want {
|
||
t.Errorf("fmtBytes(%d) = %q, want %q", in, got, want)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestBudgetMark(t *testing.T) {
|
||
cases := []struct {
|
||
r repoRow
|
||
want string
|
||
}{
|
||
{repoRow{Error: "boom"}, "✗"},
|
||
{repoRow{BudgetViolations: 0}, "✓"},
|
||
{repoRow{BudgetViolations: 2}, "⚠ 2"},
|
||
}
|
||
for _, c := range cases {
|
||
if got := budgetMark(c.r); got != c.want {
|
||
t.Errorf("budgetMark(%+v) = %q, want %q", c.r, got, c.want)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestHumanInt(t *testing.T) {
|
||
cases := map[int64]string{
|
||
0: "0",
|
||
999: "999",
|
||
1000: "1,000",
|
||
1234567: "1,234,567",
|
||
-1234: "-1,234",
|
||
}
|
||
for in, want := range cases {
|
||
if got := humanInt(in); got != want {
|
||
t.Errorf("humanInt(%d) = %q, want %q", in, got, want)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestResolveCacheDir_PrecedenceOrder(t *testing.T) {
|
||
// Flag wins over env wins over default.
|
||
t.Setenv("GORTEX_BENCH_CACHE", "/from-env")
|
||
if got := resolveCacheDir("/from-flag"); got != "/from-flag" {
|
||
t.Errorf("flag should win: got %q", got)
|
||
}
|
||
if got := resolveCacheDir(""); got != "/from-env" {
|
||
t.Errorf("env should win when flag empty: got %q", got)
|
||
}
|
||
t.Setenv("GORTEX_BENCH_CACHE", "")
|
||
got := resolveCacheDir("")
|
||
if got == "" {
|
||
t.Error("default should not be empty")
|
||
}
|
||
}
|