fix: x/tx/signing/textual: use standardized Timestamp+Duration comparators in tests (#15762)

This commit is contained in:
Emmanuel T Odeke 2023-04-10 00:12:44 +02:00 committed by GitHub
parent ec6af615f6
commit eb52f03acb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 6 deletions

View File

@ -10,7 +10,6 @@ import (
"cosmossdk.io/x/tx/signing/textual"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
dpb "google.golang.org/protobuf/types/known/durationpb"
)
@ -54,7 +53,7 @@ func TestDurationJSON(t *testing.T) {
msg := val.Message().Interface()
require.IsType(t, &dpb.Duration{}, msg)
duration := msg.(*dpb.Duration)
require.True(t, proto.Equal(duration, tc.Proto), "%v vs %v", duration, tc.Proto)
require.Equal(t, duration.AsDuration(), tc.Proto.AsDuration(), "%v vs %v", duration, tc.Proto)
})
}
}

View File

@ -2,8 +2,13 @@ package textual_test
import (
"context"
"encoding/json"
"os"
"testing"
"google.golang.org/protobuf/reflect/protoreflect"
tspb "google.golang.org/protobuf/types/known/timestamppb"
"cosmossdk.io/x/tx/signing/textual"
)
@ -28,3 +33,71 @@ func FuzzIntValueRendererParse(f *testing.F) {
_, _ = ivr.Parse(ctx, []textual.Screen{{Content: input}})
})
}
func FuzzTimestampValueRendererParse(f *testing.F) {
if testing.Short() {
f.Skip()
}
// 1. Firstly add some seed valid content.
f.Add("2006-01-02T15:04:05Z")
f.Add("1970-01-01T00:00:00.00000001Z")
f.Add("2022-07-14T11:22:20.983Z")
f.Add("1969-12-31T23:59:59Z")
// 2. Now fuzz it.
tvr := textual.NewTimestampValueRenderer()
ctx := context.Background()
f.Fuzz(func(t *testing.T, input string) {
_, _ = tvr.Parse(ctx, []textual.Screen{{Content: input}})
})
}
func FuzzTimestampJSONParseToParseRoundTrip(f *testing.F) {
// 1. Use the seeds from testdata and mutate them.
seed, err := os.ReadFile("./internal/testdata/timestamp.json")
if err != nil {
f.Fatal(err)
}
f.Add(seed)
f.Fuzz(func(t *testing.T, input []byte) {
var testCases []timestampJsonTest
if err := json.Unmarshal(input, &testCases); err != nil {
return
}
for _, tc := range testCases {
rend := textual.NewTimestampValueRenderer()
// If it successfully JSON unmarshals let's test it out.
var screens []textual.Screen
var err error
if tc.Proto != nil {
screens, err = rend.Format(context.Background(), protoreflect.ValueOf(tc.Proto.ProtoReflect()))
if err != nil {
continue
}
}
val, err := rend.Parse(context.Background(), screens)
if err != nil {
continue
}
msg := val.Message().Interface()
gotTs, ok := msg.(*tspb.Timestamp)
if !ok {
t.Fatalf("Wrong type for timestamp: %T", msg)
}
// Please avoid using proto.Equal to compare timestamps given they aren't
// in standardized form and will produce false positives for example given input:
// []byte(`[{"proto":{"nanos":1000000000}}]`)
// Per issue: https://github.com/cosmos/cosmos-sdk/issues/15761
if !gotTs.AsTime().Equal(tc.Proto.AsTime()) {
t.Fatalf("Roundtrip mismatch\n\tGot: %#v\n\tWant: %#v", gotTs, tc.Proto)
}
}
})
}

View File

@ -0,0 +1,2 @@
go test fuzz v1
string("")

View File

@ -0,0 +1,2 @@
go test fuzz v1
string("\xb0\x1b\x16d@L0@'")

View File

@ -0,0 +1,2 @@
go test fuzz v1
[]byte("[{\"proto\":{\"nAnos\":1000000000}}]")

View File

@ -11,7 +11,6 @@ import (
"cosmossdk.io/x/tx/signing/textual"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
dur "google.golang.org/protobuf/types/known/durationpb"
tspb "google.golang.org/protobuf/types/known/timestamppb"
@ -31,12 +30,21 @@ type timestampJsonTest struct {
Text string
}
func TestTimestampJsonTestcases(t *testing.T) {
func TestTimestampJsonTestcasesTestData(t *testing.T) {
raw, err := os.ReadFile("./internal/testdata/timestamp.json")
require.NoError(t, err)
testTimestampJsonTestcases(t, raw)
}
// Tests to ensure that we compare standardized forms of the final timestamppb.Timestamp.
// Please see issue https://github.com/cosmos/cosmos-sdk/issues/15761
func TestTimestampJsonTestcasesExtraneousNanos(t *testing.T) {
testTimestampJsonTestcases(t, []byte(`[{"proto":{"nAnos":1000000000},"text":"1970-01-01T00:00:01Z"}]`))
}
func testTimestampJsonTestcases(t *testing.T, raw []byte) {
var testcases []timestampJsonTest
err = json.Unmarshal(raw, &testcases)
err := json.Unmarshal(raw, &testcases)
require.NoError(t, err)
for i, tc := range testcases {
@ -64,7 +72,11 @@ func TestTimestampJsonTestcases(t *testing.T) {
msg := val.Message().Interface()
require.IsType(t, &tspb.Timestamp{}, msg)
timestamp := msg.(*tspb.Timestamp)
require.True(t, proto.Equal(timestamp, tc.Proto))
// Please avoid using proto.Equal to compare timestamps given they aren't
// in standardized form and will produce false positives for example given input:
// []byte(`[{"proto":{"nanos":1000000000}}]`)
// Per issue: https://github.com/cosmos/cosmos-sdk/issues/15761
require.True(t, timestamp.AsTime().Equal(tc.Proto.AsTime()))
})
}
}