📖 7 min read (~ 1300 words).

Upstream Tracking

Upstream Tracking

We continue to monitor and selectively adopt changes from the upstream repository.

Implemented from Upstream

  • #1513 - JSONEqBytes
  • #1803 - Kind/NotKind assertions
  • #1805 - IsOfTypeT[T] generic assertions
  • #1685 - Partial iterator support (SeqContainsT variants)
  • #1828 - Spew panic fixes
  • #1611 - Goroutine leak in Eventually/Never (drove the context-based pollCondition refactor)
  • #1825, #1818, #1223, #1813, #1822, #1829 - Various bug fixes
  • #1606, #1087 - Consistently assertion
  • #1848 - Subset error message
  • #1839 - InEpsilonSymmetric (number equality with symmetric role)
  • #1840 - JSON/YAML Redactor pattern (dynamic input redaction, inspired by Insta)
  • #1859 - Channel assertions (Blocked / NotBlocked)
  • #1860 - ErrorAsType / NotErrorAsType (go1.26+, adapted with a typed *E target)
  • #1940, #1942 - ErrorNotContains (the opposite of ErrorContains)
  • #1908 - Contains with a rune or byte element
  • #1874, #1875 - quoted string values in Empty / NotEmpty failures
  • #1931, #1899 - InEpsilonSlice keeps the caller’s message
  • #1898 - InDeltaMapValues names the failing key

Superseded by Our Implementation

  • #1801 - Error message on large collections for Len
  • #1845 - Fix Eventually/Never regression (superseded by context-based pollCondition)
  • #1830 - CollectT.Halt() (implemented as CollectT.Cancel() in v2.4 — see CHANGES)
  • #1819 - Handle unexpected exits (handled by per-tick goroutine wrap in v2.4)
  • #1824 - Spew testing (superseded by property-based fuzzing)

Review frequency: Quarterly (last review: August 2026, next review: November 2026)


Appendix: Upstream References

This table catalogs all upstream PRs and issues from github.com/stretchr/testify that we have processed.

Implemented (Adapted or Merged)

ReferenceTypeSummaryOutcome in Fork
#994PRColorize expected vs actual values✅ Adapted into enable/color module with themes and configuration
#1087IssueConsistently assertion✅ Adapted
#1223PRDisplay uint values in decimal instead of hex✅ Merged - Applied to diff output
#1232PRColorized output for expected/actual/errors✅ Adapted into enable/color module
#1356PRpanic(nil) handling for Go 1.21+✅ Merged - Updated panic assertions
#1467PRColorized output with terminal detection✅ Adapted into enable/color module (most mature implementation)
#1480PRColorized diffs via TESTIFY_COLORED_DIFF env var✅ Adapted with env var support in enable/color
#1513PRJSONEqBytes for byte slice JSON comparison✅ Merged - Added to JSON domain
#1606PRConsistently assertion✅ Adapted
#1611IssueGoroutine leak in Eventually/Never✅ Fixed by using context.Context (consolidation into single pollCondition function)
#1685PRIterator support (iter.Seq) for Contains/ElementsMatch✅ Partial - Implemented SeqContainsT and SeqNotContainsT only
#1772PRYAML library migration to maintained fork✅ Adapted - Used gopkg.in/yaml.v3 in optional enable/yaml module
#1797PRCodegen package consolidation and licensing✅ Adapted - Complete rewrite of code generation system
#1803PRKind/NotKind assertions✅ Merged - Added to Type domain
#1805IssueGeneric IsOfType[T]() without dummy value✅ Implemented - IsOfTypeT and IsNotOfTypeT in Type domain
#1813IssuePanic with unexported fields✅ Fixed via #1828 in internalized spew
#1816IssueFix panic on unexported struct key in map✅ Fixed in internalized go-spew
#1818PRFix panic on invalid regex in Regexp/NotRegexp✅ Merged - Added graceful error handling
#1822IssueDeterministic map ordering in diffs✅ Fixed in internalized go-spew
#1825PRFix panic using EqualValues with incomparable types✅ Merged - Enhanced type safety in EqualValues
#1826IssueType safety with spew (meta-issue)✅ Addressed through comprehensive fuzzing and fixes
#1828PRFixed panic with unexported fields in maps✅ Merged into internalized go-spew
#1829IssueFix time.Time rendering in diffs✅ Fixed in internalized go-spew
#1848PRSubset (garbled error message)✅ Adapted
#1839PRNumber equality with symmetric role✅ Adapted
#1840IssueJSON presence check without exact values✅ Adapted
#1859IssueChannel assertions✅ Adapted
#1860Issue (PR #1861)ErrorAsType[E] for Go 1.26+✅ Adapted - implemented as ErrorAsType / NotErrorAsType with a typed *E target and a bool return (not the upstream (E, bool) shape), guarded by //go:build go1.26. First user of the codegen go-version guard.
#1915IssueStack overflow on recursive walk✅ Fixed (detected and fixed independently)
#1874, #1875PRQuote string values in empty assertion failures✅ Adapted - Empty/NotEmpty render a string value with %q, so whitespace and the empty string stay visible. NotEmpty also gained the truncation every other failure message has.
#1898PRInclude the map key in InDeltaMapValues error message✅ Adapted - the per-key call carries at key <k>, alongside the caller’s own message.
#1899, #1931PRPass the custom message through InEpsilonSlice✅ Adapted - the index context no longer replaces the caller’s message; both are joined.
#1908PRContains is not rune-safe on Unicode strings✅ Adapted - Contains(t, "héllo", 'é') compared against the literal "<int32 Value>". Dispatch is now on the element kind (string, rune, byte, defined string type). The invalid-UTF-8 half of the upstream report is deliberately left as byte semantics.
#1940, #1942Issue/PRErrorNotContains assertion✅ Adapted - implemented as ErrorNotContains in the error domain, the opposite of ErrorContains: a nil error fails, and so does an error whose message contains the substring.
#1878Issuediff hunk size✅ Implemented (forward only) - parameterized hunk size is an API challenge

Superseded by Our Implementation

ReferenceTypeSummaryWhy Superseded
#1801IssueLen error printing large collectionsDuplicate issue upstream. This is fixed by generalized truncation
#1845PRFix Eventually/Never regressionSuperseded by context-based pollCondition implementation (we don’t have this bug)
#1819PRHandle unexpected exits in EventuallyImplemented in v2.4 via per-tick goroutine wrap — a runtime.Goexit in the condition only aborts the current tick
#1824PRSpew testing improvementsSuperseded by property-based fuzzing with random type generator
#1830PRCollectT.Halt() for stopping testsImplemented in v2.4 as CollectT.Cancel() — see CHANGES
#1937PRErrorAsType (go1.27)Superseded by our implementation

Under Consideration (Monitoring)

ReferenceTypeSummaryStatus
#1576Issue/PREqualValues assertion🔍 Monitoring #1863- Wrong equality when comparing float32 and float64
#1945PRMust helper🔍 Monitoring #1945- Syntactic sugar to hand a value directly when no error

Informational (Not Implemented)

ReferenceTypeSummaryOutcome
#1147IssueGeneral discussion about generics adoptionℹ️ Marked “Not Planned” upstream - We implemented our own generics approach (55 functions)
#1308PRComprehensive refactor with generic type parametersℹ️ Draft for v2.0.0 upstream - We took a different approach with the same objective
#1591, #1601PR + IssueNoFieldIsZero recursive zero-value assertionWon’t do - Considered and prototyped (2026-04-26). Same conclusion as upstream maintainers: semantics is too ambiguous (map keys, []byte, pointer targets, unexported fields, cycles, time.Time-style smart-zero types) and overlaps too heavily with Equal for legitimate use cases. Each pitfall fix adds a knob; full version is a struct validator, not an assertion.
#1776Issuerequire doc-comment examples call functions that return no valueℹ️ Same defect in our generated API pages, found and fixed independently: the signature tables listed a bool return for every require row. Nothing to adopt.
#1862IssueCollectT redesign / testing.TB interopWon’t do (for now) - Studied in depth (2026-04-17). All four design options (interface widening, embedding *testing.T, opt-in CollectTB wrapper, CollectT-as-interface) carry visible costs; Go’s testing.TB.private() blocks any clean proxy. Workaround for affected users is a 3-line per-helper adapter. Revisit if traction warrants the breaking churn.

Summary Statistics

CategoryCount
Implemented/Merged35
Superseded6
Monitoring1
Informational5
Total Processed47

Note: This fork maintains an active relationship with upstream, regularly reviewing new PRs and issues. The quarterly review process ensures we stay informed about upstream developments while maintaining our architectural independence.


See Also