Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

201 lines
5.2 KiB
Go

package main
import (
"encoding/json"
"strings"
"testing"
"time"
"github.com/zzet/gortex/internal/graph"
)
func TestPctMs_NearestRank(t *testing.T) {
// Build [1, 2, …, 100] ms.
xs := make([]time.Duration, 100)
for i := range xs {
xs[i] = time.Duration(i+1) * time.Millisecond
}
cases := map[int]float64{
50: 51.0, // idx = 50*100/100 = 50 → sorted[50] = 51ms
95: 96.0, // idx = 95 → 96ms
99: 100.0, // idx = 99 → 100ms
}
for p, want := range cases {
got := pctMs(xs, p)
if got != want {
t.Errorf("pctMs(%d) = %.2f, want %.2f", p, got, want)
}
}
}
func TestPctMs_EmptyReturnsZero(t *testing.T) {
if got := pctMs(nil, 50); got != 0 {
t.Errorf("pctMs(nil) = %.2f, want 0", got)
}
}
func TestPctMs_SingleSampleAllPctReturnIt(t *testing.T) {
xs := []time.Duration{5 * time.Millisecond}
for _, p := range []int{50, 95, 99} {
if got := pctMs(xs, p); got != 5.0 {
t.Errorf("pctMs(single, %d) = %.2f, want 5.0", p, got)
}
}
}
func TestMeanMs(t *testing.T) {
xs := []time.Duration{
1 * time.Millisecond,
2 * time.Millisecond,
3 * time.Millisecond,
4 * time.Millisecond,
}
if got := meanMs(xs); got != 2.5 {
t.Errorf("meanMs = %.2f, want 2.5", got)
}
if got := meanMs(nil); got != 0 {
t.Errorf("meanMs(nil) = %.2f, want 0", 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 TestFilterCalls_KeepsRequestedSubset(t *testing.T) {
g := graph.New()
all := defaultCalls(g, 10)
got := filterCalls(all, []string{"graph_stats", "search_symbols"})
if len(got) != 2 {
t.Fatalf("got %d, want 2", len(got))
}
gotNames := map[string]bool{}
for _, c := range got {
gotNames[c.Tool] = true
}
if !gotNames["graph_stats"] || !gotNames["search_symbols"] {
t.Errorf("got %v, want graph_stats + search_symbols", gotNames)
}
}
func TestDefaultCalls_PopulatesSubstrate(t *testing.T) {
g := graph.New()
g.AddNode(&graph.Node{ID: "f.go::Sym", Name: "Sym", Kind: graph.KindFunction, FilePath: "f.go"})
g.AddNode(&graph.Node{ID: "file:f.go", Kind: graph.KindFile, FilePath: "f.go"})
calls := defaultCalls(g, 50)
if len(calls) == 0 {
t.Fatal("defaultCalls returned 0 entries")
}
// At least the headline tools must be present.
want := map[string]bool{
"graph_stats": true, "search_symbols": true,
"get_symbol_source": true, "smart_context": true,
}
got := map[string]bool{}
for _, c := range calls {
got[c.Tool] = true
}
for w := range want {
if !got[w] {
t.Errorf("default call set missing %q", w)
}
}
}
func TestDefaultCalls_SkipsTargetlessSubstrate(t *testing.T) {
g := graph.New()
// No function / method nodes → get_symbol_source / get_callers /
// find_usages should report SkipIfMissing=true.
calls := defaultCalls(g, 10)
for _, c := range calls {
if c.Tool == "get_symbol_source" || c.Tool == "get_callers" || c.Tool == "find_usages" {
if c.SkipIfMissing == nil || !c.SkipIfMissing(g) {
t.Errorf("%s should skip when no callable symbols available", c.Tool)
}
}
}
}
func TestRenderMarkdown_HasHeaderAndRows(t *testing.T) {
rows := []result{
{Tool: "graph_stats", Iters: 200, P50Ms: 1.2, P95Ms: 4.5, P99Ms: 8.9, MeanMs: 2.0, MaxMs: 12.5},
{Tool: "smart_context", Iters: 40, P50Ms: 50.0, P95Ms: 200.0, P99Ms: 300.0, MeanMs: 80.0, MaxMs: 350.0},
{Tool: "skipped_one", Skipped: "no substrate"},
}
g := graph.New()
md := renderMarkdown(rows, "/tmp/repo", g)
for _, want := range []string{
"# Daemon-mode MCP-tool latency",
"| graph_stats |",
"| smart_context |",
"| skipped_one |",
"skipped:",
"**Summary:**",
"2/3 tools",
} {
if !strings.Contains(md, want) {
t.Errorf("markdown missing %q\n----\n%s", want, md)
}
}
}
func TestRenderCSV_HasHeaderAndRows(t *testing.T) {
rows := []result{
{Tool: "graph_stats", Iters: 200, P50Ms: 1.2, P95Ms: 4.5, P99Ms: 8.9},
}
out := renderCSV(rows)
if !strings.HasPrefix(out, "tool,iters,p50_ms,p95_ms,p99_ms,") {
t.Errorf("CSV header missing or wrong:\n%s", out)
}
if !strings.Contains(out, "graph_stats,200,") {
t.Errorf("CSV body missing graph_stats row:\n%s", out)
}
}
func TestMustMarshalJSON_RoundTrip(t *testing.T) {
rows := []result{
{Tool: "graph_stats", Iters: 100, P95Ms: 5.5, P99Ms: 8.2},
}
raw := mustMarshalJSON(rows)
var got []result
if err := json.Unmarshal(raw, &got); err != nil {
t.Fatalf("round-trip: %v", err)
}
if len(got) != 1 || got[0].Tool != "graph_stats" || got[0].P95Ms != 5.5 {
t.Errorf("round-trip lost data: %+v", got)
}
}
func TestSummary_AllSkippedYieldsExplicitMessage(t *testing.T) {
rows := []result{{Tool: "x", Skipped: "y"}, {Tool: "z", Skipped: "w"}}
got := summary(rows)
if !strings.Contains(got, "no tools ran") {
t.Errorf("summary should explicitly say no tools ran, got %q", got)
}
}
func TestSummary_MedianP95AndP99(t *testing.T) {
rows := []result{
{Tool: "a", P95Ms: 1, P99Ms: 2},
{Tool: "b", P95Ms: 5, P99Ms: 10},
{Tool: "c", P95Ms: 10, P99Ms: 20},
}
got := summary(rows)
// Median p95 of [1, 5, 10] = 5
if !strings.Contains(got, "Median p95 across tools: 5.0ms") {
t.Errorf("summary missing median p95=5.0ms; got:\n%s", got)
}
}