vendor tsgo

This commit is contained in:
2026-07-09 16:50:43 -04:00
parent c06ea2e5a4
commit 98978e4930
5804 changed files with 1556156 additions and 101 deletions

View File

@@ -0,0 +1,193 @@
package fswatch
import "testing"
// testingT is the subset of [testing.T] (and [testing.TB]) used by every
// test in this package. It exists so that the per-backend test bodies
// dispatched through [runForEachWatcher] can be re-run by a fake T that
// captures Fatal/Skip via panic+recover instead of terminating the
// goroutine. macOS event-delivery stalls (which are not regressions but
// environmental flakes) can then be transparently retried before
// propagating to the real *testing.T.
//
// Restricted vs *testing.T:
// - No Parallel, Run, or other subtest plumbing.
// - No Setenv / Chdir (would race across retries).
//
// All helper functions in this file accept testingT rather than
// *testing.T so they work with both the real test runner and the retry
// wrapper.
type testingT interface {
Helper()
Cleanup(fn func())
TempDir() string
Name() string
Log(args ...any)
Logf(format string, args ...any)
Error(args ...any)
Errorf(format string, args ...any)
Fatal(args ...any)
Fatalf(format string, args ...any)
Skip(args ...any)
Skipf(format string, args ...any)
SkipNow()
Failed() bool
}
// Compile-time assertion that *testing.T satisfies testingT.
var _ testingT = (*testing.T)(nil)
// retryAttempts is the number of times runForEachWatcher will re-run a
// failing per-backend test body before propagating the failure to the
// real *testing.T. The per-event timeouts inside the body scale with
// the attempt number (1×, 5×, 15×), so the fast-path is cheap and only
// real environmental flakes pay the cost of longer waits.
const retryAttempts = 3
// retryTimeoutScale returns the multiplier applied to per-event timeouts
// on the given (1-based) attempt. 1× on first try, 5× on second,
// 15× on third.
func retryTimeoutScale(attempt int) int {
switch attempt {
case 1:
return 1
case 2:
return 5
default:
return 15
}
}
// retryT is a fake [testingT] used to run a test body and decide
// whether it passed without committing the verdict to the real
// *testing.T on intermediate attempts.
//
// Most methods (Helper, Cleanup, TempDir, Name, Log, Logf) are direct
// passthroughs to the real T so messages stream to test output as they
// happen rather than waiting for a verdict. Error/Errorf record a
// failure locally but also log to the real T (so the message is visible
// even on a successful retry). Fatal/Fatalf/Skip[Now/f] additionally
// panic with [retryBail] to unwind the goroutine; the retry driver
// recovers and either retries or surfaces a final failure.
type retryT struct {
t *testing.T
// attempt is 1-based and increases on each retry. Per-event
// timeouts in helpers (waitForEvent etc.) scale from this so the
// fast-path uses a short deadline and only retries pay the cost of
// longer waits.
attempt int
failed bool
skipped bool
}
// retryBail is panicked by Fatal/Fatalf/SkipNow/Skip[f] to abort the
// test body. The retry driver recovers it and inspects the retryT
// state to decide whether to retry, surface a skip, or accept success.
type retryBail struct{}
func newRetryT(t *testing.T, attempt int) *retryT {
return &retryT{t: t, attempt: attempt}
}
func (r *retryT) Helper() { r.t.Helper() }
func (r *retryT) Cleanup(fn func()) { r.t.Cleanup(fn) }
func (r *retryT) TempDir() string { return r.t.TempDir() }
func (r *retryT) Name() string { return r.t.Name() }
func (r *retryT) Log(args ...any) { r.t.Helper(); r.t.Log(args...) }
func (r *retryT) Logf(format string, args ...any) { r.t.Helper(); r.t.Logf(format, args...) }
func (r *retryT) Failed() bool { return r.failed }
func (r *retryT) Error(args ...any) {
r.t.Helper()
r.failed = true
r.t.Log(args...)
}
func (r *retryT) Errorf(format string, args ...any) {
r.t.Helper()
r.failed = true
r.t.Logf(format, args...)
}
func (r *retryT) Fatal(args ...any) {
r.t.Helper()
r.failed = true
r.t.Log(args...)
panic(retryBail{})
}
func (r *retryT) Fatalf(format string, args ...any) {
r.t.Helper()
r.failed = true
r.t.Logf(format, args...)
panic(retryBail{})
}
func (r *retryT) Skip(args ...any) {
r.t.Helper()
r.skipped = true
r.t.Log(args...)
panic(retryBail{})
}
func (r *retryT) Skipf(format string, args ...any) {
r.t.Helper()
r.skipped = true
r.t.Logf(format, args...)
panic(retryBail{})
}
func (r *retryT) SkipNow() {
r.skipped = true
panic(retryBail{})
}
// runWithRetry runs body up to [retryAttempts] times. Each attempt uses
// a fresh retryT whose attempt counter scales the per-event timeouts in
// the test helpers. Returns on the first attempt that does not fail
// (Skip and success both terminate the loop). On final failure the real
// T is marked failed; intermediate failures are visible in test output
// as Log messages (from Error/Errorf/Fatal/Fatalf streaming through)
// followed by a "retry: ..." log noting the next attempt.
//
// On the fast-path (body passes first try), this is one call with
// negligible overhead over a direct invocation.
func runWithRetry(t *testing.T, body func(testingT)) {
t.Helper()
for attempt := 1; attempt <= retryAttempts; attempt++ {
r := newRetryT(t, attempt)
func() {
defer func() {
if rec := recover(); rec != nil {
if _, ok := rec.(retryBail); !ok {
// Not our panic; resurface.
panic(rec)
}
}
}()
body(r)
}()
if r.skipped {
t.SkipNow()
return
}
if !r.failed {
if attempt > 1 {
t.Logf("retry: succeeded on attempt %d/%d", attempt, retryAttempts)
}
return
}
if attempt < retryAttempts {
t.Logf("retry: attempt %d/%d failed, retrying with %d× timeout scale",
attempt, retryAttempts, retryTimeoutScale(attempt+1))
}
}
t.Errorf("retry: gave up after %d attempts", retryAttempts)
}