forked from TrueCloudLab/frostfs-api-go
Evgenii Stratonikov
47a48969b0
Test the generated code, do not write yet another marshaling routine in tests. Before: ``` ok git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/proto 0.003s coverage: 55.6% of statements ``` After: ``` ok git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/proto 0.003s coverage: 80.0% of statements ``` Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
155 lines
5.6 KiB
Go
155 lines
5.6 KiB
Go
package proto_test
|
|
|
|
import (
|
|
"math"
|
|
"math/rand"
|
|
"testing"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/proto/test"
|
|
"github.com/stretchr/testify/require"
|
|
goproto "google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
type protoInt interface {
|
|
~int32 | ~uint32 | ~int64 | ~uint64
|
|
}
|
|
|
|
func nonZero[T protoInt]() T {
|
|
var r T
|
|
for r == 0 {
|
|
r = T(rand.Uint64())
|
|
}
|
|
return r
|
|
}
|
|
|
|
func TestStableMarshalSingle(t *testing.T) {
|
|
t.Run("empty", func(t *testing.T) {
|
|
input := &test.Primitives{}
|
|
require.Zero(t, input.StableSize())
|
|
|
|
r := input.StableMarshal(nil)
|
|
require.Empty(t, r)
|
|
})
|
|
|
|
marshalCases := []struct {
|
|
name string
|
|
input *test.Primitives
|
|
}{
|
|
{name: "bytes", input: &test.Primitives{FieldA: []byte{1, 2, 3}}},
|
|
{name: "string", input: &test.Primitives{FieldB: "123"}},
|
|
{name: "bool", input: &test.Primitives{FieldC: true}},
|
|
{name: "int32", input: &test.Primitives{FieldD: nonZero[int32]()}},
|
|
{name: "uint32", input: &test.Primitives{FieldE: nonZero[uint32]()}},
|
|
{name: "int64", input: &test.Primitives{FieldF: nonZero[int64]()}},
|
|
{name: "uint64", input: &test.Primitives{FieldG: nonZero[uint64]()}},
|
|
{name: "uint64", input: &test.Primitives{FieldI: nonZero[uint64]()}},
|
|
{name: "float64", input: &test.Primitives{FieldJ: math.Float64frombits(12345677890)}},
|
|
{name: "fixed32", input: &test.Primitives{FieldK: nonZero[uint32]()}},
|
|
{name: "enum, positive", input: &test.Primitives{FieldH: test.Primitives_POSITIVE}},
|
|
{name: "enum, negative", input: &test.Primitives{FieldH: test.Primitives_NEGATIVE}},
|
|
}
|
|
for _, tc := range marshalCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
r := tc.input.StableMarshal(nil)
|
|
require.Equal(t, len(r), tc.input.StableSize())
|
|
require.NotEmpty(t, r)
|
|
|
|
var actual test.Primitives
|
|
require.NoError(t, goproto.Unmarshal(r, &actual))
|
|
|
|
// Compare each field directly, because proto-generated code has private fields.
|
|
require.Equal(t, tc.input.FieldA, actual.FieldA)
|
|
require.Equal(t, tc.input.FieldB, actual.FieldB)
|
|
require.Equal(t, tc.input.FieldC, actual.FieldC)
|
|
require.Equal(t, tc.input.FieldD, actual.FieldD)
|
|
require.Equal(t, tc.input.FieldE, actual.FieldE)
|
|
require.Equal(t, tc.input.FieldF, actual.FieldF)
|
|
require.Equal(t, tc.input.FieldG, actual.FieldG)
|
|
require.Equal(t, tc.input.FieldI, actual.FieldI)
|
|
require.Equal(t, tc.input.FieldJ, actual.FieldJ)
|
|
require.Equal(t, tc.input.FieldK, actual.FieldK)
|
|
require.Equal(t, tc.input.FieldH, actual.FieldH)
|
|
})
|
|
}
|
|
}
|
|
|
|
func randIntSlice[T protoInt](n int, includeZero bool) []T {
|
|
r := make([]T, n)
|
|
if n == 0 {
|
|
return r
|
|
}
|
|
for i := range r {
|
|
r[i] = T(rand.Uint64())
|
|
}
|
|
if includeZero {
|
|
r[0] = 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
func TestStableMarshalRep(t *testing.T) {
|
|
t.Run("empty", func(t *testing.T) {
|
|
marshalCases := []struct {
|
|
name string
|
|
input *test.RepPrimitives
|
|
}{
|
|
{name: "default", input: &test.RepPrimitives{}},
|
|
{name: "bytes", input: &test.RepPrimitives{FieldA: [][]byte{}}},
|
|
{name: "string", input: &test.RepPrimitives{FieldB: []string{}}},
|
|
{name: "int32", input: &test.RepPrimitives{FieldC: []int32{}}},
|
|
{name: "uint32", input: &test.RepPrimitives{FieldD: []uint32{}}},
|
|
{name: "int64", input: &test.RepPrimitives{FieldE: []int64{}}},
|
|
{name: "uint64", input: &test.RepPrimitives{FieldF: []uint64{}}},
|
|
{name: "uint64", input: &test.RepPrimitives{FieldFu: []uint64{}}},
|
|
}
|
|
|
|
for _, tc := range marshalCases {
|
|
require.Zero(t, tc.input.StableSize())
|
|
|
|
r := tc.input.StableMarshal(nil)
|
|
require.Empty(t, r)
|
|
}
|
|
})
|
|
|
|
marshalCases := []struct {
|
|
name string
|
|
input *test.RepPrimitives
|
|
}{
|
|
{name: "bytes", input: &test.RepPrimitives{FieldA: [][]byte{{1, 2, 3}}}},
|
|
{name: "string", input: &test.RepPrimitives{FieldB: []string{"123"}}},
|
|
{name: "int32", input: &test.RepPrimitives{FieldC: randIntSlice[int32](1, true)}},
|
|
{name: "int32", input: &test.RepPrimitives{FieldC: randIntSlice[int32](2, true)}},
|
|
{name: "int32", input: &test.RepPrimitives{FieldC: randIntSlice[int32](2, false)}},
|
|
{name: "uint32", input: &test.RepPrimitives{FieldD: randIntSlice[uint32](1, true)}},
|
|
{name: "uint32", input: &test.RepPrimitives{FieldD: randIntSlice[uint32](2, true)}},
|
|
{name: "uint32", input: &test.RepPrimitives{FieldD: randIntSlice[uint32](2, false)}},
|
|
{name: "int64", input: &test.RepPrimitives{FieldE: randIntSlice[int64](1, true)}},
|
|
{name: "int64", input: &test.RepPrimitives{FieldE: randIntSlice[int64](2, true)}},
|
|
{name: "int64", input: &test.RepPrimitives{FieldE: randIntSlice[int64](2, false)}},
|
|
{name: "uint64", input: &test.RepPrimitives{FieldF: randIntSlice[uint64](1, true)}},
|
|
{name: "uint64", input: &test.RepPrimitives{FieldF: randIntSlice[uint64](2, true)}},
|
|
{name: "uint64", input: &test.RepPrimitives{FieldF: randIntSlice[uint64](2, false)}},
|
|
{name: "uint64", input: &test.RepPrimitives{FieldFu: randIntSlice[uint64](1, true)}},
|
|
{name: "uint64", input: &test.RepPrimitives{FieldFu: randIntSlice[uint64](2, true)}},
|
|
{name: "uint64", input: &test.RepPrimitives{FieldFu: randIntSlice[uint64](2, false)}},
|
|
}
|
|
for _, tc := range marshalCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
r := tc.input.StableMarshal(nil)
|
|
require.Equal(t, len(r), tc.input.StableSize())
|
|
require.NotEmpty(t, r)
|
|
|
|
var actual test.RepPrimitives
|
|
require.NoError(t, goproto.Unmarshal(r, &actual))
|
|
|
|
// Compare each field directly, because proto-generated code has private fields.
|
|
require.Equal(t, tc.input.FieldA, actual.FieldA)
|
|
require.Equal(t, tc.input.FieldB, actual.FieldB)
|
|
require.Equal(t, tc.input.FieldC, actual.FieldC)
|
|
require.Equal(t, tc.input.FieldD, actual.FieldD)
|
|
require.Equal(t, tc.input.FieldE, actual.FieldE)
|
|
require.Equal(t, tc.input.FieldF, actual.FieldF)
|
|
require.Equal(t, tc.input.FieldFu, actual.FieldFu)
|
|
})
|
|
}
|
|
}
|