Skip to content

Commit 56b5954

Browse files
authored
Prepare release v2.4.0 (#64)
* feat(condition): added support for Consistently * feat(condition): added support for func(context.Context) error to async assertions Eventually and Consistently > NOTE: refrained from adding func(ctx) error to Never, > as it introduces a confusing logic which is awkward to document and prone to errors. **BREAKING**: removed Condition type - no value added to alias func() bool > Part of our plan to clean up unnecessary extra types chore: removed bash script for local testing with hugo (now a go "script") > Part of our plan to superseded all local bash by go scripts. > Bash has a place and it's in CI only. doc: added testable examples for async assertions (Eventually, etc) doc: fixup typos, introduced wordlist for future spellcheckers (currently experimented locally only) doc: updated changes & upstream tracking references Signed-off-by: Frederic BIDON <[email protected]>
1 parent adf1c9a commit 56b5954

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2056
-683
lines changed

.claude/CLAUDE.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ codegen/
9292
7. `r.Equal(...)` - fatal forward method
9393
8. `r.Equalf(..., "msg")` - fatal forward format variant
9494

95-
With 76 assertion functions, this generates 608 functions automatically.
95+
With 127 assertion functions, this generates 840 functions automatically.
9696

9797
### Dependency Isolation Strategy
9898
- **internal/spew**: Internalized copy of go-spew for pretty-printing values
@@ -141,7 +141,7 @@ cd codegen && go run . -output-packages assert,require -include-doc
141141

142142
# Preview documentation site locally
143143
cd hack/doc-site/hugo
144-
./gendoc.sh
144+
go run gendoc.go
145145
# Visit http://localhost:1313/testify/
146146

147147
# The Hugo site auto-reloads on changes to docs/doc-site/
@@ -278,7 +278,7 @@ The codegen also generates domain-organized documentation for a Hugo static site
278278
**Hugo static site setup:**
279279
Located in `hack/doc-site/hugo/`:
280280
- **hugo.yaml** - Main Hugo configuration
281-
- **gendoc.sh** - Development server script
281+
- **gendoc.go** - Development server script
282282
- **themes/hugo-relearn** - Documentation theme
283283
- Mounts generated content from `docs/doc-site/`
284284

@@ -289,7 +289,7 @@ go generate ./...
289289

290290
# Then start the Hugo dev server
291291
cd hack/doc-site/hugo
292-
./gendoc.sh
292+
go run gendoc.go
293293

294294
# Visit http://localhost:1313/testify/
295295
```
@@ -489,10 +489,10 @@ func TestParseTestExamples(t *testing.T) {
489489
- Drop-in replacement for stretchr/testify
490490

491491
**The Math:**
492-
- 76 assertion functions × 8 variants = 608 functions
493-
- Old model: Manually maintain 608 functions across multiple packages
494-
- New model: Write 76 functions once, generate the rest
495-
- Result: 87% reduction in manual code maintenance
492+
- 127 assertion functions × 4-8 variants = 840 functions
493+
- Old model: Manually maintain 840 functions across multiple packages
494+
- New model: Write 127 functions once, generate the rest
495+
- Result: 85% reduction in manual code maintenance
496496

497497
### Technical Innovations
498498

@@ -555,7 +555,7 @@ hack/doc-site/hugo/ # Note: Temporary location
555555
├── hugo.yaml # Main Hugo configuration
556556
├── testify.yaml # Generated config with version info
557557
├── testify.yaml.template # Template for testify.yaml
558-
├── gendoc.sh # Development server launcher
558+
├── gendoc.go # Development server launcher
559559
├── README.md, TODO.md # Documentation and planning
560560
├── themes/
561561
│ └── hugo-relearn/ # Documentation theme

.github/wordlist.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
API
22
APIs
3+
BDD
34
BSON
45
CI
56
CIDR
67
CLI
78
CLIs
9+
CodeFactor
10+
CodeQL
811
CSV
912
DCO
1013
DockerHub
@@ -22,15 +25,20 @@ IDs
2225
IP
2326
IPs
2427
ISBN
28+
ISC
2529
JSON
30+
JUnit
2631
Kubernetes
32+
LOC
2733
Markdown
2834
NaN
2935
OAI
3036
OAuth
3137
OpenAPI
38+
PHPUnit
3239
PR
3340
PRs
41+
PyTest
3442
README
3543
SSN
3644
TCP
@@ -64,17 +72,23 @@ bitmask
6472
bson
6573
bytesize
6674
cancelled
75+
cgo
6776
ci
6877
cidr
6978
cli
7079
clis
80+
codebase
7181
codecov
7282
codegen
83+
colorizer
84+
colorizers
7385
config
7486
configs
7587
csv
7688
customizable
7789
dependabot
90+
dereference
91+
dereferencing
7892
deserialize
7993
deserialized
8094
deserializer
@@ -87,6 +101,7 @@ flattener
87101
fuzzying
88102
gc
89103
github
104+
globals
90105
go-openapi
91106
godoc
92107
golang
@@ -102,6 +117,7 @@ https
102117
hugo
103118
i.e.
104119
id
120+
impactful
105121
implementor
106122
implementors
107123
initialism
@@ -116,6 +132,7 @@ json
116132
jsonschema
117133
k8s
118134
kubernetes
135+
lifecycle
119136
linter
120137
linters
121138
listA
@@ -128,6 +145,7 @@ marshaling
128145
middleware
129146
middlewares
130147
mixin
148+
monorepo
131149
multipart
132150
mutex
133151
oai
@@ -136,33 +154,42 @@ oauth2
136154
openapi
137155
param
138156
params
157+
prepend
158+
prepended
139159
rebase
140160
rebased
161+
roadmap
141162
redeclare
142163
repo
143164
repos
144165
roundtrip
145166
roundtripper
146167
schema
147168
schemas
169+
semver
148170
serialize
149171
serialized
150172
serializer
151173
sexualized
174+
spdx
152175
ssn
176+
stdlib
153177
struct
154178
structs
155179
submodule
156180
subpackage
157181
substring
158182
swagger
183+
testify's
159184
tls
160185
toolchain
161186
ui
162187
ulid
188+
uncategorized
163189
unmarshal
164190
unmarshaled
165191
unmarshaling
192+
unexported
166193
untyped
167194
uri
168195
url
@@ -177,4 +204,5 @@ validators
177204
waitFor
178205
workspace
179206
workspaces
207+
xunit
180208
yaml

CODE_OF_CONDUCT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
5555
## Enforcement
5656

5757
Instances of abusive, harassing, or otherwise unacceptable behavior may be
58-
reported by contacting the project team at [email protected]. All
58+
reported by contacting the project team at <[email protected]>. All
5959
complaints will be reviewed and investigated and will result in a response that
6060
is deemed necessary and appropriate to the circumstances. The project team is
6161
obligated to maintain confidentiality with regard to the reporter of an incident.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Testify/v2
22

33
<!-- Badges: s[roadmap]tatus -->
4-
[![Tests][test-badge]][test-url] [![Coverage][cov-badge]][cov-url] [![CI vuln scan][vuln-scan-badge]][vuln-scan-url] [![CodeQL][codeql-badge]][codeql-url]
4+
[![Tests][test-badge]][test-url] [![Coverage][cov-badge]][cov-url] [![CI vulnerability scan][vuln-scan-badge]][vuln-scan-url] [![CodeQL][codeql-badge]][codeql-url]
55
<!-- Badges: release & docker images -->
66
<!-- Badges: code quality -->
77
<!-- Badges: license & compliance -->
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package assert_test
5+
6+
import (
7+
"context"
8+
"errors"
9+
"fmt"
10+
"sync/atomic"
11+
"testing"
12+
"time"
13+
14+
"github.com/go-openapi/testify/v2/assert"
15+
)
16+
17+
// ExampleEventually_asyncReady demonstrates polling a condition that becomes true
18+
// after a few attempts, simulating an asynchronous operation completing.
19+
func ExampleEventually_asyncReady() {
20+
t := new(testing.T) // normally provided by test
21+
22+
// Simulate an async operation that completes after a short delay.
23+
var ready atomic.Bool
24+
go func() {
25+
time.Sleep(30 * time.Millisecond)
26+
ready.Store(true)
27+
}()
28+
29+
result := assert.Eventually(t, ready.Load, 200*time.Millisecond, 10*time.Millisecond)
30+
31+
fmt.Printf("eventually ready: %t", result)
32+
33+
// Output: eventually ready: true
34+
}
35+
36+
// ExampleEventually_healthCheck demonstrates [Eventually] with a
37+
// func(context.Context) error condition, polling until the operation
38+
// succeeds (returns nil).
39+
func ExampleEventually_healthCheck() {
40+
t := new(testing.T) // normally provided by test
41+
42+
// Simulate a service that becomes healthy after a few attempts.
43+
var attempts atomic.Int32
44+
healthCheck := func(_ context.Context) error {
45+
if attempts.Add(1) < 3 {
46+
return errors.New("service not ready")
47+
}
48+
49+
return nil
50+
}
51+
52+
result := assert.Eventually(t, healthCheck, 200*time.Millisecond, 10*time.Millisecond)
53+
54+
fmt.Printf("eventually healthy: %t", result)
55+
56+
// Output: eventually healthy: true
57+
}
58+
59+
// ExampleNever_noSpuriousEvents demonstrates asserting that a condition never becomes true
60+
// during the observation period.
61+
func ExampleNever_noSpuriousEvents() {
62+
t := new(testing.T) // normally provided by test
63+
64+
// A channel that should remain empty during the test.
65+
events := make(chan struct{}, 1)
66+
67+
result := assert.Never(t, func() bool {
68+
select {
69+
case <-events:
70+
return true // event received = condition becomes true = Never fails
71+
default:
72+
return false
73+
}
74+
}, 100*time.Millisecond, 10*time.Millisecond)
75+
76+
fmt.Printf("never received: %t", result)
77+
78+
// Output: never received: true
79+
}
80+
81+
// ExampleConsistently_invariant demonstrates asserting that a condition remains true
82+
// throughout the entire observation period.
83+
func ExampleConsistently_invariant() {
84+
t := new(testing.T) // normally provided by test
85+
86+
// A counter that stays within bounds during the test.
87+
var counter atomic.Int32
88+
counter.Store(5)
89+
90+
result := assert.Consistently(t, func() bool {
91+
return counter.Load() < 10
92+
}, 100*time.Millisecond, 10*time.Millisecond)
93+
94+
fmt.Printf("consistently under limit: %t", result)
95+
96+
// Output: consistently under limit: true
97+
}
98+
99+
// ExampleConsistently_alwaysHealthy demonstrates [Consistently] with a
100+
// func(context.Context) error condition, asserting that the operation
101+
// always succeeds (returns nil) throughout the observation period.
102+
func ExampleConsistently_alwaysHealthy() {
103+
t := new(testing.T) // normally provided by test
104+
105+
// Simulate a service that stays healthy.
106+
healthCheck := func(_ context.Context) error {
107+
return nil // always healthy
108+
}
109+
110+
result := assert.Consistently(t, healthCheck, 100*time.Millisecond, 10*time.Millisecond)
111+
112+
fmt.Printf("consistently healthy: %t", result)
113+
114+
// Output: consistently healthy: true
115+
}

0 commit comments

Comments
 (0)