// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package io import ( "flag" "fmt" "os" "runtime" "testing" "time" ) // TestMain installs a heap watchdog for the whole package run. The io // tests are hostile-input tests by design: they feed crafted headers to // the readers and check that nothing panics and nothing grows without // bound. A regression therefore cannot fail politely, it allocates: a // hard-link cycle and a deep group chain both took the host down once. // The watchdog turns any such runaway into an immediate panic that // unwinds the offending code path, so the worst case is a failed test // rather than an OOM kill of the editor that started it. func TestMain(m *testing.M) { // The aggregate read budget bounds what one input may allocate // legally; the watchdog sits an order above it. Fuzzing runs many // workers holding inputs at once and the engine carries its own // corpus and coverage bookkeeping, so the fuzz run watches a wider // ceiling while still catching the unbounded growth the guard // exists for: a runaway reaches any finite cap in seconds. // // The flags are parsed here, before the ceiling is decided: the // test flags are only registered at TestMain and m.Run parses them // later, so an earlier read of test.fuzz sees its empty default and // the fuzz ceiling never fires. flag.Parse() const plainCap = 3 << 30 ceiling := int64(plainCap) if f := flag.Lookup("test.fuzz"); f != nil && f.Value.String() != "" { ceiling = 32 << 30 } stop := make(chan struct{}) go func() { ticker := time.NewTicker(20 * time.Millisecond) defer ticker.Stop() for { select { case <-stop: return case <-ticker.C: var m runtime.MemStats runtime.ReadMemStats(&m) if int64(m.HeapAlloc) > ceiling { panic(fmt.Sprintf("io test binary heap above %d GiB: a reader is allocating without bound", ceiling>>30)) } } } }() code := m.Run() close(stop) os.Exit(code) }