package aiaudit import ( "context" "strings" "testing" "github.com/google/uuid" ) // Call metadata is attached in layers: the job sets company/user/job once, then // each product narrows it. A later WithCall must not wipe what an outer scope set. func TestWithCall_mergesWithoutClearing(t *testing.T) { t.Parallel() company, user, job, product := uuid.New(), uuid.New(), uuid.New(), uuid.New() ctx := WithCall(context.Background(), CallContext{ CompanyID: company, UserID: user, JobID: job, Role: RoleProcessing, }) ctx = WithCall(ctx, CallContext{RawProductID: product}) got := FromContext(ctx) if got.CompanyID != company || got.UserID != user || got.JobID != job { t.Fatalf("outer scope lost: %+v", got) } if got.RawProductID != product { t.Fatalf("product not attached: %+v", got) } if got.Role != RoleProcessing { t.Fatalf("role lost: %q", got.Role) } // A narrower scope may override the role (categorize inside a processing job). ctx = WithCall(ctx, CallContext{Role: RoleCategorize}) if got := FromContext(ctx); got.Role != RoleCategorize || got.JobID != job { t.Fatalf("role override broke context: %+v", got) } } func TestFromContext_zeroValueWhenAbsent(t *testing.T) { t.Parallel() if got := FromContext(context.Background()); got != (CallContext{}) { t.Fatalf("expected zero CallContext, got %+v", got) } //nolint:staticcheck // explicitly asserting the nil-ctx guard if got := FromContext(nil); got != (CallContext{}) { t.Fatalf("nil ctx must be safe, got %+v", got) } } // Capture must never be able to take down the call it observes. func TestRecorder_nilIsNoOp(t *testing.T) { t.Parallel() var r *Recorder r.Record(context.Background(), Call{System: "x"}) // must not panic if got := NewRecorder(nil); got != nil { t.Fatal("nil pool must yield a nil (no-op) recorder") } } // A runaway reply must not write an unbounded row. func TestClamp_boundsBody(t *testing.T) { t.Parallel() short := strings.Repeat("a", 10) if clamp(short) != short { t.Fatal("short bodies must pass through unchanged") } long := strings.Repeat("b", maxBodyRunes+500) got := clamp(long) if len([]rune(got)) <= maxBodyRunes { t.Fatalf("clamped body should keep the cap plus a marker, got %d runes", len([]rune(got))) } if !strings.HasSuffix(got, "[truncated by aiaudit]") { t.Fatal("clamped body must say it was truncated") } }