blob: 94de4212d78f95ac70a80fdf51f74325a2e073ac [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package order
import (
"math/rand"
"sort"
"testing"
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/reflect/protoreflect"
)
type fieldDesc struct {
index int
name protoreflect.FullName
number protoreflect.FieldNumber
extension bool
oneofIndex int // non-zero means within oneof; negative means synthetic
protoreflect.FieldDescriptor
}
func (d fieldDesc) Index() int { return d.index }
func (d fieldDesc) Name() protoreflect.Name { return d.name.Name() }
func (d fieldDesc) FullName() protoreflect.FullName { return d.name }
func (d fieldDesc) Number() protoreflect.FieldNumber { return d.number }
func (d fieldDesc) IsExtension() bool { return d.extension }
func (d fieldDesc) ContainingOneof() protoreflect.OneofDescriptor {
switch {
case d.oneofIndex < 0:
return oneofDesc{index: -d.oneofIndex, synthetic: true}
case d.oneofIndex > 0:
return oneofDesc{index: +d.oneofIndex, synthetic: false}
default:
return nil
}
}
type oneofDesc struct {
index int
synthetic bool
protoreflect.OneofDescriptor
}
func (d oneofDesc) Index() int { return d.index }
func (d oneofDesc) IsSynthetic() bool { return d.synthetic }
func TestFieldOrder(t *testing.T) {
tests := []struct {
label string
order FieldOrder
fields []fieldDesc
}{{
label: "LegacyFieldOrder",
order: LegacyFieldOrder,
fields: []fieldDesc{
// Extension fields sorted first by field number.
{number: 2, extension: true},
{number: 4, extension: true},
{number: 100, extension: true},
{number: 120, extension: true},
// Non-extension fields that are not within a oneof
// sorted next by field number.
{number: 1},
{number: 5, oneofIndex: -10}, // synthetic oneof
{number: 10},
{number: 11, oneofIndex: -9}, // synthetic oneof
{number: 12},
// Non-synthetic oneofs sorted last by index.
{number: 13, oneofIndex: 4},
{number: 3, oneofIndex: 5},
{number: 9, oneofIndex: 5},
{number: 7, oneofIndex: 8},
},
}, {
label: "NumberFieldOrder",
order: NumberFieldOrder,
fields: []fieldDesc{
{number: 1, index: 5, name: "c"},
{number: 2, index: 2, name: "b"},
{number: 3, index: 3, name: "d"},
{number: 5, index: 1, name: "a"},
{number: 7, index: 7, name: "e"},
},
}, {
label: "IndexNameFieldOrder",
order: IndexNameFieldOrder,
fields: []fieldDesc{
// Non-extension fields sorted first by index.
{index: 0, number: 5, name: "c"},
{index: 2, number: 2, name: "a"},
{index: 4, number: 4, name: "b"},
{index: 7, number: 6, name: "d"},
// Extension fields sorted last by full name.
{index: 3, number: 1, name: "d.a", extension: true},
{index: 5, number: 3, name: "e", extension: true},
{index: 1, number: 7, name: "g", extension: true},
},
}}
for _, tt := range tests {
t.Run(tt.label, func(t *testing.T) {
want := tt.fields
got := append([]fieldDesc(nil), want...)
for i, j := range rand.Perm(len(got)) {
got[i], got[j] = got[j], got[i]
}
sort.Slice(got, func(i, j int) bool {
return tt.order(got[i], got[j])
})
if diff := cmp.Diff(want, got,
cmp.Comparer(func(x, y fieldDesc) bool { return x == y }),
); diff != "" {
t.Errorf("order mismatch (-want +got):\n%s", diff)
}
})
}
}
func TestKeyOrder(t *testing.T) {
tests := []struct {
label string
order KeyOrder
keys []interface{}
}{{
label: "GenericKeyOrder",
order: GenericKeyOrder,
keys: []interface{}{false, true},
}, {
label: "GenericKeyOrder",
order: GenericKeyOrder,
keys: []interface{}{int32(-100), int32(-99), int32(-10), int32(-9), int32(-1), int32(0), int32(+1), int32(+9), int32(+10), int32(+99), int32(+100)},
}, {
label: "GenericKeyOrder",
order: GenericKeyOrder,
keys: []interface{}{int64(-100), int64(-99), int64(-10), int64(-9), int64(-1), int64(0), int64(+1), int64(+9), int64(+10), int64(+99), int64(+100)},
}, {
label: "GenericKeyOrder",
order: GenericKeyOrder,
keys: []interface{}{uint32(0), uint32(1), uint32(9), uint32(10), uint32(99), uint32(100)},
}, {
label: "GenericKeyOrder",
order: GenericKeyOrder,
keys: []interface{}{uint64(0), uint64(1), uint64(9), uint64(10), uint64(99), uint64(100)},
}, {
label: "GenericKeyOrder",
order: GenericKeyOrder,
keys: []interface{}{"", "a", "aa", "ab", "ba", "bb", "\u0080", "\u0080\u0081", "\u0082\u0080"},
}}
for _, tt := range tests {
t.Run(tt.label, func(t *testing.T) {
var got, want []protoreflect.MapKey
for _, v := range tt.keys {
want = append(want, protoreflect.ValueOf(v).MapKey())
}
got = append(got, want...)
for i, j := range rand.Perm(len(got)) {
got[i], got[j] = got[j], got[i]
}
sort.Slice(got, func(i, j int) bool {
return tt.order(got[i], got[j])
})
if diff := cmp.Diff(want, got, cmp.Transformer("", protoreflect.MapKey.Interface)); diff != "" {
t.Errorf("order mismatch (-want +got):\n%s", diff)
}
})
}
}