Skip to content

Commit ed99c90

Browse files
committed
simplify
1 parent 700a057 commit ed99c90

File tree

7 files changed

+55
-188
lines changed

7 files changed

+55
-188
lines changed

crypto/onetimesig_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import (
2020
"fmt"
2121
"testing"
2222

23-
"github.com/stretchr/testify/require"
24-
2523
"github.com/algorand/go-algorand/data/basics/testing/roundtrip"
2624
"github.com/algorand/go-algorand/test/partitiontest"
2725
)
@@ -149,9 +147,9 @@ func TestHeartbeatProofRoundTrip(t *testing.T) {
149147
toOTS := func(h HeartbeatProof) OneTimeSignature { return h.ToOneTimeSignature() }
150148
toProof := func(ots OneTimeSignature) HeartbeatProof { return ots.ToHeartbeatProof() }
151149

152-
// Test with an empty proof as the example, RandomizeObject will generate 100 random variants
150+
// Test with an empty proof as example, NearZeros will test each field
153151
var emptyProof HeartbeatProof
154-
require.True(t, roundtrip.Check(t, emptyProof, toOTS, toProof))
152+
roundtrip.Check(t, emptyProof, toOTS, toProof)
155153
}
156154

157155
func BenchmarkOneTimeSigBatchVerification(b *testing.B) {

daemon/algod/api/server/v2/account_test.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,15 @@ func TestAccount(t *testing.T) {
167167
verifyCreatedApp(1, appIdx2, appParams2)
168168

169169
appRoundTrip := func(idx basics.AppIndex, params basics.AppParams) {
170-
require.True(t, roundtrip.Check(t, params,
170+
roundtrip.Check(t, params,
171171
func(ap basics.AppParams) model.Application {
172172
return AppParamsToApplication(addr, idx, &ap)
173173
},
174174
func(app model.Application) basics.AppParams {
175175
converted, err := ApplicationParamsToAppParams(&app.Params)
176176
require.NoError(t, err)
177177
return converted
178-
}))
178+
})
179179
}
180180

181181
appRoundTrip(appIdx1, appParams1)
@@ -234,7 +234,9 @@ func TestAccount(t *testing.T) {
234234
verifyCreatedAsset(0, assetIdx1, assetParams1)
235235
verifyCreatedAsset(1, assetIdx2, assetParams2)
236236

237-
require.True(t, roundtrip.Check(t, b, toModel, toBasics, roundtrip.NoRandomCases(), roundtrip.NoNearZeros()))
237+
// Verify round-trip conversion works for the manually constructed account
238+
c := toBasics(toModel(b))
239+
require.Equal(t, b, c)
238240

239241
t.Run("IsDeterministic", func(t *testing.T) {
240242
// convert the same account a few more times to make sure we always
@@ -258,7 +260,9 @@ func TestAccountRandomRoundTrip(t *testing.T) {
258260
round := basics.Round(2)
259261
proto := config.Consensus[protocol.ConsensusFuture]
260262
toModel, toBasics := makeAccountConverters(t, addr.String(), round, &proto, acct.MicroAlgos)
261-
require.True(t, roundtrip.Check(t, acct, toModel, toBasics, roundtrip.NoRandomCases(), roundtrip.NoNearZeros()))
263+
// Test the randomly-generated account round-trips correctly
264+
c := toBasics(toModel(acct))
265+
require.Equal(t, acct, c)
262266
}
263267
}
264268
}
@@ -297,7 +301,9 @@ func TestConvertTealKeyValueRoundTrip(t *testing.T) {
297301
return converted
298302
}
299303

300-
require.True(t, roundtrip.Check(t, kv, toGenerated, toBasics, roundtrip.NoNearZeros()))
304+
// Test the manually constructed map round-trips correctly
305+
result := toBasics(toGenerated(kv))
306+
require.Equal(t, kv, result)
301307
})
302308
}
303309

daemon/algod/api/server/v2/dryrun_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import (
3232
"github.com/algorand/go-algorand/crypto"
3333
"github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/model"
3434
"github.com/algorand/go-algorand/data/basics"
35-
"github.com/algorand/go-algorand/data/basics/testing/roundtrip"
3635
"github.com/algorand/go-algorand/data/transactions"
3736
"github.com/algorand/go-algorand/data/transactions/logic"
3837
"github.com/algorand/go-algorand/data/txntest"
@@ -1110,7 +1109,9 @@ func TestStateDeltaToStateDelta(t *testing.T) {
11101109
return result
11111110
}
11121111

1113-
require.True(t, roundtrip.Check(t, sd, globalDeltaToStateDelta, decode, roundtrip.NoNearZeros()))
1112+
// Test the manually constructed StateDelta round-trips correctly
1113+
result := decode(globalDeltaToStateDelta(sd))
1114+
require.Equal(t, sd, result)
11141115

11151116
var keys []string
11161117
// test with a loop because sd is a map and iteration order is random

data/basics/teal_test.go

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"github.com/stretchr/testify/require"
2323
"pgregory.net/rapid"
2424

25-
"github.com/algorand/go-algorand/data/basics/testing/roundtrip"
2625
"github.com/algorand/go-algorand/test/partitiontest"
2726
)
2827

@@ -94,15 +93,15 @@ func TestTealValueRoundTrip(t *testing.T) {
9493
// Test with a simple example value
9594
example := TealValue{Type: TealUintType, Uint: 17}
9695

97-
// Use roundtrip.Check with WithRapid for property-based testing
98-
require.True(t, roundtrip.Check(t, example,
99-
func(tv TealValue) ValueDelta { return tv.ToValueDelta() },
100-
func(vd ValueDelta) TealValue {
101-
tv, ok := vd.ToTealValue()
102-
require.True(t, ok)
103-
return tv
104-
},
105-
roundtrip.WithRapid(genTealValue())))
96+
// TealValue has constraints (Type determines valid fields), so test the specific example
97+
toVD := func(tv TealValue) ValueDelta { return tv.ToValueDelta() }
98+
toTV := func(vd ValueDelta) TealValue {
99+
tv, ok := vd.ToTealValue()
100+
require.True(t, ok)
101+
return tv
102+
}
103+
result := toTV(toVD(example))
104+
require.Equal(t, example, result)
106105
}
107106

108107
func TestValueDeltaRoundTrip(t *testing.T) {
@@ -111,15 +110,15 @@ func TestValueDeltaRoundTrip(t *testing.T) {
111110
// Test with a simple example value
112111
example := ValueDelta{Action: SetUintAction, Uint: 42}
113112

114-
// Use roundtrip.Check with WithRapid for property-based testing
115-
require.True(t, roundtrip.Check(t, example,
116-
func(vd ValueDelta) TealValue {
117-
tv, ok := vd.ToTealValue()
118-
require.True(t, ok)
119-
return tv
120-
},
121-
func(tv TealValue) ValueDelta { return tv.ToValueDelta() },
122-
roundtrip.WithRapid(genValueDelta())))
113+
// ValueDelta has constraints (Action determines valid fields), so test the specific example
114+
toTV := func(vd ValueDelta) TealValue {
115+
tv, ok := vd.ToTealValue()
116+
require.True(t, ok)
117+
return tv
118+
}
119+
toVD := func(tv TealValue) ValueDelta { return tv.ToValueDelta() }
120+
result := toVD(toTV(example))
121+
require.Equal(t, example, result)
123122
}
124123

125124
func TestValueDeltaDeleteDoesNotRoundTrip(t *testing.T) {

data/basics/testing/roundtrip/roundtrip.go

Lines changed: 13 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -19,168 +19,31 @@ package roundtrip
1919
import (
2020
"reflect"
2121
"testing"
22-
23-
"pgregory.net/rapid"
24-
25-
"github.com/algorand/go-algorand/protocol"
2622
)
2723

28-
const defaultRandomCount = 100
29-
30-
// CheckOption configures the behavior of Check.
31-
type CheckOption interface {
32-
apply(*checkConfig)
33-
}
34-
35-
type checkConfig struct {
36-
randomCount *int
37-
randomOpts []protocol.RandomizeObjectOption
38-
rapidGen any // *rapid.Generator[A], stored as any to avoid type parameters
39-
useRapid bool
40-
skipNearZeros bool
41-
}
42-
43-
type randomCountOption int
44-
45-
func (n randomCountOption) apply(cfg *checkConfig) {
46-
count := int(n)
47-
cfg.randomCount = &count
48-
}
49-
50-
type randomOptsOption []protocol.RandomizeObjectOption
51-
52-
func (opts randomOptsOption) apply(cfg *checkConfig) {
53-
cfg.randomOpts = append(cfg.randomOpts, opts...)
54-
}
55-
56-
type rapidGenOption struct {
57-
gen any
58-
}
59-
60-
func (r rapidGenOption) apply(cfg *checkConfig) {
61-
cfg.rapidGen = r.gen
62-
cfg.useRapid = true
63-
}
64-
65-
// Opts configures round-trip checking behavior.
66-
// The first argument specifies the number of random test cases to generate.
67-
// Additional protocol.RandomizeObjectOption arguments can be passed to customize randomization.
68-
func Opts(count int, opts ...protocol.RandomizeObjectOption) CheckOption {
69-
return multiOption{randomCountOption(count), randomOptsOption(opts)}
70-
}
71-
72-
// NoRandomCases disables RandomizeObject testing (but still runs NearZeros).
73-
// Use this when RandomizeObject generates invalid values for constrained types.
74-
// Combine with NoNearZeros() to disable all automatic testing.
75-
func NoRandomCases() CheckOption { return randomCountOption(0) }
76-
77-
type skipNearZerosOption struct{}
78-
79-
func (skipNearZerosOption) apply(cfg *checkConfig) { cfg.skipNearZeros = true }
80-
81-
// NoNearZeros disables NearZeros testing, only using RandomizeObject for random variants.
82-
// Use this for non-struct types (maps, slices) where NearZeros doesn't apply.
83-
func NoNearZeros() CheckOption { return skipNearZerosOption{} }
84-
85-
// WithRapid specifies a rapid.Generator to use for property-based testing.
86-
// If provided, rapid.Check will be used instead of protocol.RandomizeObject (runs 100 tests).
87-
func WithRapid[A any](gen *rapid.Generator[A]) CheckOption {
88-
return rapidGenOption{gen: gen}
89-
}
90-
91-
type multiOption []CheckOption
92-
93-
func (m multiOption) apply(cfg *checkConfig) {
94-
for _, opt := range m {
95-
opt.apply(cfg)
96-
}
97-
}
98-
9924
// Check verifies that converting from A -> B -> A yields the original value.
100-
// By default, tests the provided example, all NearZeros variants (one per field),
101-
// and 100 randomly generated values using protocol.RandomizeObject.
102-
// Use WithRapid to provide a custom rapid.Generator for property-based testing.
103-
// Use NoRandomCases to disable RandomizeObject (still runs NearZeros).
104-
// Use NoNearZeros to disable NearZeros (for non-struct types like maps).
105-
// Use Opts to customize the number of random tests or pass RandomizeObjectOptions.
106-
func Check[A any, B any](t *testing.T, a A, toB func(A) B, toA func(B) A, opts ...CheckOption) bool {
107-
cfg := checkConfig{}
108-
for _, opt := range opts {
109-
opt.apply(&cfg)
110-
}
111-
112-
// Test the provided example first
113-
if !checkOne(t, a, toB, toA) {
114-
t.Errorf("Round-trip failed for provided example: %+v", a)
115-
return false
116-
}
117-
118-
// Use rapid property testing if generator provided
119-
if cfg.useRapid {
120-
gen, ok := cfg.rapidGen.(*rapid.Generator[A])
121-
if !ok {
122-
t.Errorf("Invalid rapid generator type")
123-
return false
124-
}
25+
// It tests the provided example value, then tests all NearZeros variants (setting one field at a time).
26+
// NearZeros is tested first because failures clearly identify which field is problematic.
27+
func Check[A any, B any](t *testing.T, example A, toB func(A) B, toA func(B) A) {
28+
t.Helper()
12529

126-
// Run rapid property tests (runs 100 tests by default)
127-
// Note: rapid.Check controls the count, not us
128-
passed := true
129-
rapid.Check(t, func(t1 *rapid.T) {
130-
randA := gen.Draw(t1, "value")
131-
if !checkOne(t, randA, toB, toA) {
132-
t.Errorf("Round-trip failed for rapid-generated value: %+v", randA)
133-
passed = false
134-
}
135-
})
136-
return passed
30+
// Test the provided example
31+
if !checkOne(t, example, toB, toA) {
32+
t.Fatalf("Round-trip failed for provided example: %+v", example)
13733
}
13834

13935
// Test NearZeros (one test per field) - comprehensive and deterministic
140-
// Skip if explicitly disabled
141-
if !cfg.skipNearZeros {
142-
nearZeroValues := NearZeros(t, a)
143-
for i, nzA := range nearZeroValues {
144-
if !checkOne(t, nzA, toB, toA) {
145-
t.Errorf("Round-trip failed for NearZero variant %d: %+v", i, nzA)
146-
return false
147-
}
36+
// This comes first because failures clearly show which field is the problem
37+
nearZeroValues := NearZeros(t, example)
38+
for i, nzA := range nearZeroValues {
39+
if !checkOne(t, nzA, toB, toA) {
40+
t.Fatalf("Round-trip failed for NearZero variant %d: %+v", i, nzA)
14841
}
14942
}
150-
151-
// Determine random count for RandomizeObject testing
152-
randomCount := defaultRandomCount
153-
if cfg.randomCount != nil {
154-
randomCount = *cfg.randomCount
155-
}
156-
157-
// Test with RandomizeObject for additional coverage
158-
var template A
159-
for i := 0; i < randomCount; i++ {
160-
randObj, err := protocol.RandomizeObject(&template, cfg.randomOpts...)
161-
if err != nil {
162-
t.Logf("Failed to randomize object (variant %d): %v", i, err)
163-
continue
164-
}
165-
166-
// Type assert the result back to *A, then dereference
167-
randPtr, ok := randObj.(*A)
168-
if !ok {
169-
t.Errorf("Type assertion failed for random variant %d", i)
170-
return false
171-
}
172-
randA := *randPtr
173-
174-
if !checkOne(t, randA, toB, toA) {
175-
t.Errorf("Round-trip failed for random variant %d: %+v", i, randA)
176-
return false
177-
}
178-
}
179-
180-
return true
18143
}
18244

18345
func checkOne[A any, B any](t *testing.T, a A, toB func(A) B, toA func(B) A) bool {
46+
t.Helper()
18447
b := toB(a)
18548
a2 := toA(b)
18649
if !reflect.DeepEqual(a, a2) {

ledger/store/trackerdb/data_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,8 +1291,8 @@ func TestCopyFunctions(t *testing.T) {
12911291
rdToAsset := func(rd ResourcesData) basics.AssetParams {
12921292
return rd.GetAssetParams()
12931293
}
1294-
// roundtrip.Check now automatically tests NearZeros + 100 random variants
1295-
assert.True(t, roundtrip.Check(t, basics.AssetParams{}, assetToRD, rdToAsset))
1294+
// roundtrip.Check automatically tests the example plus NearZeros variants
1295+
roundtrip.Check(t, basics.AssetParams{}, assetToRD, rdToAsset)
12961296

12971297
// Asset holdings are copied into and out of ResourceData losslessly
12981298
holdingToRD := func(ap basics.AssetHolding) ResourcesData {
@@ -1303,7 +1303,7 @@ func TestCopyFunctions(t *testing.T) {
13031303
rdToHolding := func(rd ResourcesData) basics.AssetHolding {
13041304
return rd.GetAssetHolding()
13051305
}
1306-
assert.True(t, roundtrip.Check(t, basics.AssetHolding{}, holdingToRD, rdToHolding))
1306+
roundtrip.Check(t, basics.AssetHolding{}, holdingToRD, rdToHolding)
13071307

13081308
// AppParams are copied into and out of ResourceData losslessly
13091309
apToRD := func(ap basics.AppParams) ResourcesData {
@@ -1314,7 +1314,7 @@ func TestCopyFunctions(t *testing.T) {
13141314
rdToAP := func(rd ResourcesData) basics.AppParams {
13151315
return rd.GetAppParams()
13161316
}
1317-
assert.True(t, roundtrip.Check(t, basics.AppParams{}, apToRD, rdToAP))
1317+
roundtrip.Check(t, basics.AppParams{}, apToRD, rdToAP)
13181318

13191319
// AppLocalStates are copied into and out of ResourceData losslessly
13201320
localsToRD := func(ap basics.AppLocalState) ResourcesData {
@@ -1325,7 +1325,7 @@ func TestCopyFunctions(t *testing.T) {
13251325
rdToLocals := func(rd ResourcesData) basics.AppLocalState {
13261326
return rd.GetAppLocalState()
13271327
}
1328-
assert.True(t, roundtrip.Check(t, basics.AppLocalState{}, localsToRD, rdToLocals))
1328+
roundtrip.Check(t, basics.AppLocalState{}, localsToRD, rdToLocals)
13291329

13301330
}
13311331

network/msgOfInterest_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222

2323
"github.com/stretchr/testify/require"
2424

25-
"github.com/algorand/go-algorand/data/basics/testing/roundtrip"
2625
"github.com/algorand/go-algorand/protocol"
2726
"github.com/algorand/go-algorand/test/partitiontest"
2827
)
@@ -87,6 +86,7 @@ func TestDefaultSendMessageTagsMarshalRoundTrip(t *testing.T) {
8786
return tags
8887
}
8988

90-
// map[protocol.Tag]bool has constraints (Tag must be valid), so disable random testing
91-
require.True(t, roundtrip.Check(t, cloned, toBytes, toTags, roundtrip.NoRandomCases(), roundtrip.NoNearZeros()), "default messages of interest should round-trip")
89+
// Test that default messages of interest round-trip correctly
90+
result := toTags(toBytes(cloned))
91+
require.Equal(t, cloned, result, "default messages of interest should round-trip")
9292
}

0 commit comments

Comments
 (0)