Core helpers for darvaza.org projects

This package contains simple mechanisms used by other darvaza.org
projects. It's not allowed to have dependencies outside of Go's Standard
Library, and if something should be on a subdirectory, it shouldn't be here.
Type Constraints
Generic type constraints for use with Go generics:
Signed - signed integer types.
Unsigned - unsigned integer types.
Integer - all integer types (signed and unsigned).
Float - floating-point types.
Complex - complex number types.
Bool - boolean type.
String - string type.
Ordered - types that support ordering operations.
Context
Context Keys
NewContextKey[T](name) - creates a new type-safe key bound to specified
type and friendly name.
ContextKey[T].WithValue(ctx, value) - safely attach value to context,
comparable to standard context.WithValue().
ContextKey[T].Get(ctx) - extracts value bound to this key in context,
returns (value, found) with nil receiver safety.
Timeout Utilities
WithTimeout(parent, duration) - equivalent to context.WithDeadline()
but takes duration instead of absolute time. Returns parent context and
no-op cancel for zero/negative durations.
WithTimeoutCause(parent, duration, cause) - equivalent to
context.WithDeadlineCause() but takes duration instead of absolute time.
Attaches custom cause error to timeout context.
Network Utilities
IP Address Functions
GetIPAddresses() - get IP addresses as netip.Addr.
GetNetIPAddresses() - get IP addresses as net.IP.
GetStringIPAddresses() - get IP addresses as strings.
AddrFromNetIP(ip) - convert net.IP to netip.Addr.
ParseAddr(s) - parse string to netip.Addr.
ParseNetIP(s) - parse string to net.IP.
Host/Port Functions
Where the standard library only splits and joins, these validate and
clean: the host comes back as canonical IP text or a Unicode name,
and the port in canonical decimal form, so 0080 is returned as 80.
Port 0 is accepted everywhere but in MakeHostPort's input.
Parsing and Splitting
SplitHostPort(hostport) - enhanced version of net.SplitHostPort that
accepts portless strings and validates both host and port, returning
them cleaned. Supports IPv6 addresses, international domain names, and
descriptive error messages.
SplitAddrPort(addrport) - splits IP address and optional port into
netip.Addr and uint16. Validates address format and port range
(0-65535); the port is 0 when the string carries none.
Joining and Construction
JoinHostPort(host, port) - enhanced version of net.JoinHostPort that
validates inputs, joins the port in canonical form, and returns a
portless host when port is empty. Properly handles IPv6 bracketing and
international domain names.
MakeHostPort(hostport, defaultPort) - constructs validated host:port
string from input with optional default port. Rejects port 0 in input
in any spelling, supports portless output when default is 0.
AddrPort(v) - extracts netip.AddrPort from various network types
(*net.TCPAddr, *net.UDPAddr, etc.), returns (AddrPort, bool).
Interface Functions
GetInterfacesNames() - get network interface names.
Generic Utilities
Zero Value Utilities
Zero Value Creation
Zero[T](_ *T) - returns the zero value for type T using a typed nil
pointer for type inference. Supports all Go types including complex generics,
interfaces, and custom types.
Zero Value Detection
IsZero(v) - reports whether a value is in an uninitialized state and ready
to be set. Answers the question: "Is this value uninitialized and ready to
be set?"
Key semantic distinctions:
- Nil vs Empty:
[]int(nil) returns true (needs initialization),
[]int{} returns false (already initialized).
- Pointer States:
(*int)(nil) returns true (can be assigned),
new(int) returns false (already points to memory).
- Interface Support: Types implementing
IsZero() bool are handled
via their method, enabling custom zero semantics.
Nil Value Detection
IsNil(v) - reports whether a value is nil (typed or untyped). Answers
the question: "Is this value nil?"
Key distinctions from IsZero:
- Scope: Only checks for nil state, not zero state.
- Basic Types:
IsNil(0) returns false (integers cannot be nil),
IsZero(0) returns true (zero integer is uninitialized).
- Collections:
IsNil([]int{}) returns false (empty slice is not nil),
IsZero([]int{}) returns false (empty slice is initialized).
- Structs:
IsNil(struct{}{}) returns false (structs cannot be nil),
IsZero(struct{}{}) returns true (zero struct is uninitialized).
Same Value Detection
IsSame(a, b) - reports whether two values are the same. For reference
types (slices, maps, pointers), compares by pointer equality. For value
types (numbers, strings, booleans), compares by equal values. Two nils
of the same type are considered the same.
Safe Comparison
AreComparable(values...) - reports whether the values are safe operands
of ==: a true result guarantees no comparison between them can panic.
Untyped nils are safe.
AreEqual(values...) - reports whether each value equals the next, as
== would decide, without ever panicking, returning (is, known bool).
Values of the same comparable type are tested with ==; otherwise typed
nils, identity, or the value's own Equal(T) bool method settle the
answer, and slices are compared element by element, one level deep.
Anything else is reported as unknown rather than resolved by deep
comparison; callers that need a decision anyway can fall back to
reflect.DeepEqual when it is not known.
Other Utilities
Coalesce[T](values...) returns the first non-zero value.
IIf[T](condition, ifTrue, ifFalse) conditional expression.
TypeName[T]() names a type parameter itself, an interface type
included, where %T on a value can only name the dynamic type it
holds.
Type Conversion
As[T,V](v) attempts to convert value to target type
AsFn[T,V](v, fn) converts value using a provided function
AsError[T](v) attempts to convert value to error
AsErrors[T](v) attempts to convert value to error slice
Slice Operations
Search and Comparison
SliceContains[T](slice, value) - deprecated, use slices.Contains.
SliceContainsFn[T](slice, value, eq) - check containment with custom
equality.
SliceEqual[T](a, b) - deprecated, use slices.Equal.
SliceEqualFn[T](a, b, eq) - deprecated, use slices.EqualFunc.
Transformation
SliceAs[T,V] / SliceAsFn[T,V] - convert slice elements to different type.
SliceMap[T1,T2](slice, fn) - transform each element with cumulative
function.
SliceReplaceFn[T](slice, fn) - replace/filter elements in-place.
SliceCopy[T](slice) - deprecated, use slices.Clone.
SliceCopyFn[T](slice, fn) - create filtered/transformed copy.
Set Operations
SliceMinus[T](a, b) - elements in a but not in b.
SliceMinusFn[T](a, b, eq) - set difference with custom equality.
SliceUnique[T](slice) - return slice with unique elements only.
SliceUniqueFn[T](slice, eq) - unique elements with custom equality.
SliceUniquify[T](ptr) - remove duplicates in-place, modify original.
SliceUniquifyFn[T](ptr, eq) - remove duplicates with custom equality.
Sorting and Ordering
SliceSort[T](slice, cmp) - deprecated, use slices.SortFunc.
SliceSortFn[T](slice, less) - sort using less function (returns bool).
SliceSortOrdered[T](slice) - deprecated, use slices.Sort.
SliceReverse[T](slice) - deprecated, use slices.Reverse.
SliceReversed[T](slice) - return reversed copy.
SliceReversedFn[T](slice, fn) - return transformed and reversed copy.
Utilities
SliceRandom[T](slice) - select random element, returns (value, found).
SliceP[T](slice,p) - return the p-th percentile of the slice (p must be
0.0-1.0). Sorts the slice in-place. Returns the zero value for empty slices
or invalid p.
List Operations (container/list)
Search and Membership
ListContains[T](list, value) - check if list contains element with default
equality.
ListContainsFn[T](list, value, eq) - check if list contains element with
custom equality function.
Iteration
ListForEach[T](list, fn) - iterate forward over list values until fn
returns true.
ListForEachElement(list, fn) - iterate forward over list elements until fn
returns true.
ListForEachBackward[T](list, fn) - iterate backward over list values until
fn returns true.
ListForEachBackwardElement(list, fn) - iterate backward over list elements
until fn returns true.
Copying and Transformation
ListCopy[T](list) - create shallow copy of list.
ListCopyFn[T](list, fn) - create filtered/transformed copy with helper
function.
Map Operations
Basic Map Functions
MapContains[K]() checks if a map contains a key.
MapValue[K,V]() returns the value for a key, or a fallback value.
Keys[K,T]() returns a slice of the keys in the map.
SortedKeys[K,T]() returns a sorted slice of the keys.
SortedValues[K,T]() returns values sorted by key.
SortedValuesCond[K,T]() returns filtered values sorted by key.
SortedValuesUnlikelyCond[K,T]() like SortedValuesCond but more efficient.
Map List Operations
MapListContains[K,T] / MapListContainsFn[K,T]
MapListForEach[K,T] / MapListForEachElement[K]
MapListInsert[K,T] / MapListAppend[K,T]
MapListInsertUnique[K,T] / MapListInsertUniqueFn[K,T]
MapListAppendUnique[K,T] / MapListAppendUniqueFn[K,T]
MapListCopy[T] / MapListCopyFn[K,V]
Map All List Operations
MapAllListContains[K,T] / MapAllListContainsFn[K,T]
MapAllListForEach[K,T] / MapAllListForEachElement[K]
Error Handling
Standard Error Variables
Predefined error values for common conditions:
ErrNotImplemented - a gap: an operation that could be implemented but
isn't.
ErrTODO - a gap meant to be closed soon; matches ErrNotImplemented.
ErrExists - resource already exists.
ErrNotExists - resource does not exist.
ErrInvalid - invalid input or state.
ErrUnsupported - an operation that can't reasonably be implemented
for the target, not a gap; an alias of errors.ErrUnsupported.
ErrNotImplemented and ErrTODO do not match it.
ErrUnknown - unknown or unspecified error.
ErrNilReceiver - method called on nil receiver.
ErrUnreachable - indicates impossible condition.
String Errors
The StringError type is an error whose message is the string itself.
Because its underlying type is string, sentinels can be declared as
constants rather than variables:
const ErrClosed core.StringError = "already closed"
- Values with equal text compare equal, so
errors.Is matches by value.
.AsError() returns nil for the empty string, following the
AsError() convention used across the package.
.OK() reports whether the string is empty (no error), the inverse of
a non-nil .AsError().
.IsZero() reports whether the string is empty, so IsZero recognises
a zero StringError through its own method.
NewStringError(format, args...) - build one from a formatted message,
returning nil when the result is empty. Without arguments the format is
used verbatim, leaving a literal % untouched.
Error Wrapping
The Unwrappable interface represents the classic Unwrap() error pattern,
implemented by WrappedError. The Errors interface represents multi-error
containers with Errors() []error.
Error wrapping functions:
Wrap(err, note) - wrap with simple string note.
Wrapf(err, format, args...) - wrap with formatted note.
QuietWrap(err, note) - wrap without including original error text.
Unwrap(err) []error - extract all sub-errors from wrapped errors.
Compound Errors
The CompoundError type aggregates multiple errors:
- Implements both
Unwrap() []error and Errors() []error interfaces.
NewCompoundError(errs...) - collect errors as given, dropping nils.
.AppendError(errs...) / .Append(err, note, args...) - add errors.
.AsError() - convert to single error or nil.
.OK() - check if no errors.
For errors reported from several goroutines, see the concurrency-safe
counterpart in darvaza.org/x/sync/errors.
Panic Handling
The PanicError type wraps panic values with stack traces:
NewPanicError() / NewPanicErrorf() - create panic errors.
NewPanicWrap() / NewPanicWrapf() - wrap existing errors as panics.
Panic() / Panicf() / PanicWrap() / PanicWrapf() - panic with
PanicError.
PanicFrom() / PanicfFrom() - panic with PanicError, its stack
starting a given number of frames above the caller.
Panic recovery utilities:
Recovered interface - marks errors from recovered panics.
AsRecovered(v) - convert recover() result to error.
Catcher type - safely call functions that might panic.
Catch(fn) - execute function, returning error if panic occurs.
defer func() {
if err := core.AsRecovered(recover()); err != nil {
}
}()
Must/Maybe Utilities
Convenience functions for common error-handling patterns:
Must[T](value T, err error) T - returns value or panics with PanicError if
err is not nil. Follows the common Go pattern of Must* functions for cases
where errors should never occur.
Maybe[T](value T, err error) T - always returns the value, ignoring any
error. When an error occurs, the returned value may be the zero value of type
T depending on the function that produced it.
MustOK[T](value T, ok bool) T - returns value or panics with PanicError if
ok is false. Useful for operations that should always succeed, such as map
access or type assertions that are guaranteed to be valid.
MaybeOK[T](value T, ok bool) T - always returns the value, ignoring the ok
flag. When ok is false, the returned value is typically the zero value of
type T from the failed operation.
MustT[T](value any) T - equivalent to MustOK(As[any, T](value)). Returns
converted value or panics with PanicError if type conversion fails.
MaybeT[T](value any) T - equivalent to MaybeOK(As[any, T](value)). Returns
converted value on success, or the zero value of type T if conversion fails.
All these utilities work together with the As[any, T] function, which returns
(value, ok) for type conversion, allowing custom handling of conversion
failures.
config := Must(loadConfig("config.json"))
conn := Must(net.Dial("tcp", "localhost:8080"))
content := Maybe(os.ReadFile("optional.txt"))
count := Maybe(strconv.Atoi(userInput))
value := MustOK(MapValue(m, "key", 0))
str := MustOK(As[any, string](v))
value := MaybeOK(MapValue(m, "key", 0))
str := MaybeOK(As[any, string](v))
str := MustT[string](value)
num := MustT[int](value)
str := MaybeT[string](value)
num := MaybeT[int](value)
if str, ok := As[any, string](value); ok {
} else {
str = "custom default"
}
For error-only preconditions (no value to return), the MustNoError family
panics through ErrUnreachable rather than returning a value:
MustNoError(err error) - panics with PanicError wrapping ErrUnreachable
if err is not nil. The no-value sibling of Must, for guarding a bare error
whose non-nil return signals an impossible path.
MustNoErrorExcept(err error, allowed ...error) - like MustNoError, but
does not panic when err matches one of the allowed errors (recursive match
via IsError).
MustNoErrorExceptFn(err error, check func(error) bool) - like
MustNoErrorExcept, but matches via a predicate (recursive match via
IsErrorFn), for allow-lists that aren't a fixed set of sentinels.
Unreachable Conditions
For indicating impossible code paths:
NewUnreachableError() - create unreachable error.
NewUnreachableErrorf() - create formatted unreachable error.
PanicUnreachable() / PanicUnreachablef() - panic with an unreachable
error, its stack starting at the caller.
PanicUnreachableFrom() / PanicUnreachablefFrom() - panic with an
unreachable error, its stack starting a given number of frames above the
caller.
The constructors create PanicError instances with stack traces.
Temporary and Timeout Errors
Special error types for network-style temporary and timeout conditions:
TemporaryError type - implements Temporary() bool and IsTemporary() bool
interfaces for marking recoverable errors.
NewTemporaryError(err) - wrap error as temporary condition.
NewTimeoutError(err) - wrap error as timeout condition with both temporary
and timeout properties.
IsTemporary(err) - recursively test if error chain contains temporary
condition via Temporary() or IsTemporary() methods.
CheckIsTemporary(err) - test single error for temporary condition without
unwrapping chain, returns (is, known) tuple.
IsTimeout(err) - recursively test if error chain contains timeout
condition via Timeout() or IsTimeout() methods.
CheckIsTimeout(err) - test single error for timeout condition without
unwrapping chain, returns (is, known) tuple.
Error Testing and Utilities
IsError(err, errs...) - recursively test whether an error chain matches
any of the targets, by identity or the error's own Is(error) bool
method.
IsErrorFn(check, errs...) / IsErrorFn2(check, errs...) - recursive
error testing with custom checker functions.
NewCheckErrorIsIn(targets) / NewCheckErrorIsIn2(targets) - build the
per-node check functions behind IsError, for composing the same
identity-or-Is matching with IsErrorFn / IsErrorFn2.
CoalesceError(errs...) - return first non-nil error from argument list.
Stack Tracing
Stack tracing utilities for debugging, error reporting, and call context:
Core Types
Frame - represents a single function call frame with source location.
Stack - slice of frames representing a complete call stack.
MaxDepth - maximum stack capture depth (32 frames).
CallStacker interface - types that can provide their call stack.
Stack Capture Functions
Frame Capture
Here() - capture the current stack frame where called. Returns nil if
capture fails. Useful for immediate calling context.
StackFrame(skip) - capture a specific frame in the call stack, skipping
the specified number of levels. Returns nil if insufficient frames.
Complete Stack Capture
StackTrace(skip) - capture complete call stack starting from skip level.
Returns empty Stack on failure. Maximum depth limited by MaxDepth.
Frame Information Methods
Function Names
Frame.Name() - full qualified function name including package path
(e.g., "darvaza.org/core.TestFunction").
Frame.FuncName() - function name only without package qualification
(e.g., "TestFunction").
Frame.PkgName() - package path portion only (e.g., "darvaza.org/core").
Frame.SplitName() - split full name into (package, function) components.
Handles generic functions by ignoring "[...]" suffixes.
Source Location
Frame.File() - full path to source file containing the function.
Frame.Line() - line number within source file (0 if unavailable).
Frame.FileLine() - formatted "file:line" string for display.
Formatting
-
Frame.Format(fmt.State, rune) - implements fmt.Formatter interface with
support for multiple format verbs:
%s - source file basename.
%d - line number.
%n - function name (short form).
%v - equivalent to %s:%d.
%+s - function name + full file path (newline separated).
%+n - full qualified function name.
%+v - equivalent to %+s:%d.
-
Stack.Format(fmt.State, rune) - formats entire stack with same verbs as
Frame plus '#' flag support:
%#s, %#n, %#v - each frame on new line.
%#+s, %#+n, %#+v - numbered frames with [index/total] prefix.
Usage Examples
frame := Here()
if frame != nil {
fmt.Printf("Called from %s at %s", frame.FuncName(), frame.FileLine())
}
stack := StackTrace(1)
fmt.Printf("Stack trace:%+v", stack)
fmt.Printf("Debug stack:%#+v", stack)
Testing Utilities
This package provides comprehensive public testing utilities for both internal
library tests and external library users.
T Interface and MockT
T interface - abstracts testing functionality for both *testing.T and
mock implementations.
MockT - thread-safe mock testing.T implementation with error/log
collection, helper tracking, state inspection (HasErrors(), HasLogs(),
LastError(), LastLog(), NumErrors(), NumLogs(), ErrorAt(i),
LogAt(i), NumHelperCalls(), Failed(), Skipped()), reset
capabilities, and full Fatal/FailNow and Skip/SkipNow support through the
Run() method.
IsMockTAbort(recovered) - reports whether a value recovered from a
panic, wrapped or not, is MockT stopping a test, for code that
recovers panics around a function that may be handed a MockT to pass
on.
Cross-Compatible Test Functions
For test utilities that need to work with both *testing.T and MockT, use
interface type assertions to detect Run() method support. This enables
nested subtests that gracefully degrade to direct function calls:
func doRun(t T, name string, fn func(T)) {
switch tt := t.(type) {
case interface { Run(string, func(*testing.T)) bool }:
tt.Run(name, func(subT *testing.T) { fn(subT) })
case interface { Run(string, func(T)) bool }:
tt.Run(name, fn)
default:
fn(t)
}
}
Test Helpers
S[T](values...) - concise slice creation: S(1, 2, 3) instead of
[]int{1, 2, 3}.
S[T]() - empty slice creation: S[string]() instead of []string{}.
Assertion Functions
All assertions return boolean results, log successful cases, and work with
both *testing.T and MockT:
Basic Assertions
AssertEqual[T](t, expected, actual, name...) - generic value comparison,
decided by AreEqual.
AssertNotEqual[T](t, expected, actual, name...) - generic inequality
comparison, decided by AreEqual.
AssertSliceEqual[T](t, expected, actual, name...) - slice comparison,
settling length and nil-ness first, then the elements via AreEqual.
AssertDeepEqual[T](t, expected, actual, name...) - value comparison using
reflect.DeepEqual.
AssertNotDeepEqual[T](t, expected, actual, name...) - inequality using
reflect.DeepEqual.
AssertSame(t, expected, actual, name...) - same value/reference comparison
using pointer equality for reference types, value equality for basic types.
AssertNotSame(t, expected, actual, name...) - different value/reference
comparison.
AssertTrue(t, condition, name...) / AssertFalse(t, condition, name...) -
boolean assertions.
AssertNil(t, value, name...) / AssertNotNil(t, value, name...) - nil
checking.
AssertContains(t, text, substring, name...) - string containment.
AssertNotContain(t, text, substring, name...) - string exclusion.
The Equal family delegates to AreEqual, so it accepts values that aren't
comparable and honours an Equal(T) bool method. AssertDeepEqual and its
Must form settle what it cannot decide — nested slices, and anything else
needing a deep traversal — which the failure names as such.
AssertSliceEqual settles shape before contents: a length difference is
reported as a count, and nil-versus-empty by name, since only nil equals nil
and both otherwise print as an indistinguishable []. Once the shape matches,
the first element known to differ is reported by index, so a long slice needn't
be diffed by eye.
Error and Type Assertions
AssertError(t, err, name...) / AssertNoError(t, err, name...) - error
presence/absence.
AssertErrorIs(t, err, target, name...) /
AssertNotErrorIs(t, err, target, name...) - error chain
presence/absence via errors.Is.
AssertErrorIsFn(t, err, targetFn, name...) - error chain checking against
a check function via IsErrorFn.
AssertErrorAs[E](t, err, name...) - error chain extraction with
errors.As, returns (match, ok).
AssertTypeIs[T](t, value, name...) - type assertion with casting, returns
(value, ok).
AssertPanic(t, fn, expectedPanic, name...) /
AssertNoPanic(t, fn, name...) - panic testing with type-aware matching.
AssertTopFrame(t, v, want, name...) - the call stack v carries (a
recovered PanicError, for one) starts at the function want, named as
Frame.FuncName() names it.
Channel and Timing Assertions
AssertEventually(t, predicate, timeout, name...) - the predicate holds
within the timeout, polled every millisecond through WaitForCond.
AssertEventuallyContext(t, ctx, predicate, name...) - the predicate
holds before the context ends, polled the same way through
WaitForCondContext.
AssertClosed[U](t, ch, timeout, name...) /
AssertOpen[U](t, ch, timeout, name...) - the channel closes within the
timeout, or stays open for it. Values met on the way are consumed and
counted in the report.
AssertQuiet[U](t, ch, timeout, name...) - nothing arrives within the
timeout, neither a value nor a close. It stops at the first event, which
the report names.
AssertReceives[U](t, ch, n, timeout, name...) - n values arrive
within one shared timeout and are returned; a close before the n-th
fails it.
Fatal Assertions
All AssertMustFoo() functions call the corresponding AssertFoo() function
and automatically call t.FailNow() if the assertion fails, terminating test
execution immediately. These follow Go testing conventions where "Fatal"
methods terminate execution, similar to t.Error() vs t.Fatal().
Key Differences:
AssertFoo() - like t.Error(), logs failure and allows test to continue.
AssertMustFoo() - like t.Fatal(), logs failure and terminates test
execution.
Fatal Assertion Functions:
AssertMustEqual[T](t, expected, actual, name...) - terminate on inequality.
AssertMustNotEqual[T](t, expected, actual, name...) - terminate on equality.
AssertMustSliceEqual[T](t, expected, actual, name...) - terminate on slice
inequality.
AssertMustDeepEqual[T](t, expected, actual, name...) - terminate on deep
inequality.
AssertMustNotDeepEqual[T](t, expected, actual, name...) - terminate on deep
equality.
AssertMustTrue(t, condition, name...) /
AssertMustFalse(t, condition, name...) - terminate on boolean mismatch.
AssertMustNil(t, value, name...) / AssertMustNotNil(t, value, name...) -
terminate on nil check failure.
AssertMustContains(t, text, substring, name...) - terminate if substring not
found.
AssertMustNotContain(t, text, substring, name...) - terminate if substring
found.
AssertMustError(t, err, name...) / AssertMustNoError(t, err, name...) -
terminate on error expectation mismatch.
AssertMustErrorIs(t, err, target, name...) - terminate on error chain
mismatch.
AssertMustErrorIsFn(t, err, targetFn, name...) - terminate on check
function mismatch.
AssertMustErrorAs[E](t, err, name...) E - terminate when no match in the
error chain, returns matched value.
AssertMustTypeIs[T](t, value, name...) T - terminate on type assertion
failure, returns cast value.
AssertMustPanic(t, fn, expectedPanic, name...) /
AssertMustNoPanic(t, fn, name...) - terminate on panic expectation mismatch.
AssertMustTopFrame(t, v, want, name...) - terminate when the call stack
starts at another function, or v carries none.
AssertMustSame(t, expected, actual, name...) /
AssertMustNotSame(t, expected, actual, name...) - terminate on same-ness
mismatch.
AssertMustEventually(t, predicate, timeout, name...) /
AssertMustEventuallyContext(t, ctx, predicate, name...) - terminate
when the predicate does not hold in time.
AssertMustClosed[U](t, ch, timeout, name...) /
AssertMustOpen[U](t, ch, timeout, name...) - terminate on channel state
mismatch.
AssertMustQuiet[U](t, ch, timeout, name...) - terminate when anything
arrives on the channel.
AssertMustReceives[U](t, ch, n, timeout, name...) - terminate when
n values do not arrive; return the values received.
Usage Examples:
AssertEqual(t, expected, actual, "value check")
AssertMustEqual(t, expected, actual, "critical value check")
if !AssertEqual(t, expected, actual, "critical value") {
t.FailNow()
}
Advanced Testing Utilities
TestCase interface - standardised interface for table-driven tests with
Name() and Test(t) methods.
RunTestCases[T TestCase](t, cases) - table-driven test runner for
TestCase implementations.
RunConcurrentTest(t, numWorkers, workerFn) - concurrent testing with
goroutines.
RunBenchmark(b, setupFn, execFn) - benchmark testing with
setup/execution phases.
Documentation
For detailed testing patterns and guidelines:
- TESTING.md - General testing patterns for all darvaza.org
projects
- TESTING_core.md - Core-specific testing patterns and
self-testing approaches
Synchronization
WaitGroup
Enhanced wait group with error handling:
WaitGroup - wait group that collects errors.
.OnError(fn) - set error handler.
.Go(fn) / .GoCatch(fn, catch) - run functions in goroutines,
catching panics.
.Wait() - wait for completion and return the first error.
.Done() - channel closed when all workers have finished.
.Err() - get first error.
A failing worker does not stop the others. When it should, see
darvaza.org/x/sync/workgroup, whose Group cancels
its tasks on the first error.
Polling
WaitForCond(predicate, timeout, step) - poll a predicate every step
until it holds or timeout elapses, reporting which. The predicate is
consulted before the deadline, so one already true passes with a zero
timeout.
WaitForCondContext(ctx, predicate, step) - the same wait ending when
the context does; a nil context means no deadline and no cancellation.
ErrGroup
Context-aware error group with cancellation:
ErrGroup - context-based error group.
.SetDefaults() - configure with defaults.
.OnError(fn) - set error handler.
.Cancel(cause) / .Context() - cancellation control.
.Go(run, shutdown) / .GoCatch(run, catch) - run functions with
context.
.Wait() - wait and return the first worker error.
.Err() - the error that initiated the shutdown, including the cause
given to .Cancel().
.Done() - channel closed when all workers have finished.
.IsCancelled() / .Cancelled() - check cancellation state.
darvaza.org/x/sync/workgroup provides a counterpart,
Group, that also runs an OnCancel handler once on any cancellation,
pairs workers with a shutdown handler bounded by a grace period, offers
Close(), and refuses new tasks once cancelled.
Deprecated
Development
Requirements: Go 1.25 or later
For detailed development setup, build commands, and AI agent guidance:
- AGENTS.md - Development guidelines, build system, and testing
patterns.
Quick Start
make all
make test
make tidy
See also