Skip to content

Commit 97e4c8c

Browse files
committed
support for map/list constraints
1 parent 0c87dbd commit 97e4c8c

15 files changed

+200
-97
lines changed

gen.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
package fauxrpc
22

33
import (
4+
"buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
45
"github.com/sudorandom/fauxrpc/private/stubs"
56
"google.golang.org/protobuf/reflect/protoreflect"
67
"google.golang.org/protobuf/reflect/protoregistry"
78
"google.golang.org/protobuf/types/dynamicpb"
89
)
910

1011
type GenOptions struct {
11-
StubDB stubs.StubDatabase
12-
MaxDepth int
12+
StubDB stubs.StubDatabase
13+
MaxDepth int
14+
extraFieldConstraints *validate.FieldConstraints
1315
}
1416

1517
func (st GenOptions) nested() GenOptions {
1618
st.MaxDepth--
19+
st.extraFieldConstraints = nil
20+
return st
21+
}
22+
23+
func (st GenOptions) withExtraFieldConstraints(constraints *validate.FieldConstraints) GenOptions {
24+
st.extraFieldConstraints = constraints
1725
return st
1826
}
1927

@@ -24,3 +32,10 @@ func newMessage(md protoreflect.MessageDescriptor) protoreflect.Message {
2432
}
2533
return mt.New()
2634
}
35+
36+
func getFieldConstraints(fd protoreflect.FieldDescriptor, opts GenOptions) *validate.FieldConstraints {
37+
if constraints := getResolver().ResolveFieldConstraints(fd); constraints != nil {
38+
return constraints
39+
}
40+
return opts.extraFieldConstraints
41+
}

gen_bool.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
)
66

77
// Bool returns a fake boolean value given a field descriptor.
8-
func Bool(fd protoreflect.FieldDescriptor) bool {
9-
constraints := getResolver().ResolveFieldConstraints(fd)
8+
func Bool(fd protoreflect.FieldDescriptor, opts GenOptions) bool {
9+
constraints := getFieldConstraints(fd, opts)
1010
if constraints == nil {
1111
return true
1212
}

gen_bool_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func TestBool(t *testing.T) {
3535
}
3636
for _, tc := range testCases {
3737
t.Run(tc.name, func(t *testing.T) {
38-
result := fauxrpc.Bool(tc.fd)
38+
result := fauxrpc.Bool(tc.fd, fauxrpc.GenOptions{})
3939
assert.Contains(t, tc.expected, result, "unexpected value")
4040
})
4141
}

gen_bytes.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ func generateBytesSimple() []byte {
1010
}
1111

1212
// Bytes returns a fake []byte value given a field descriptor.
13-
func Bytes(fd protoreflect.FieldDescriptor) []byte {
14-
constraints := getResolver().ResolveFieldConstraints(fd)
13+
func Bytes(fd protoreflect.FieldDescriptor, opts GenOptions) []byte {
14+
constraints := getFieldConstraints(fd, opts)
1515
if constraints == nil {
1616
return generateBytesSimple()
1717
}

gen_enum.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ func enumSimple(fd protoreflect.FieldDescriptor) protoreflect.EnumNumber {
1212
}
1313

1414
// Enum returns a fake enum value given a field descriptor.
15-
func Enum(fd protoreflect.FieldDescriptor) protoreflect.EnumNumber {
16-
constraints := getResolver().ResolveFieldConstraints(fd)
15+
func Enum(fd protoreflect.FieldDescriptor, opts GenOptions) protoreflect.EnumNumber {
16+
constraints := getFieldConstraints(fd, opts)
1717
if constraints == nil {
1818
return enumSimple(fd)
1919
}

gen_fields.go

+34-34
Original file line numberDiff line numberDiff line change
@@ -4,69 +4,69 @@ import (
44
"google.golang.org/protobuf/reflect/protoreflect"
55
)
66

7-
var kindToGenerator = map[protoreflect.Kind]func(fd protoreflect.FieldDescriptor) *protoreflect.Value{
8-
protoreflect.BoolKind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
9-
v := protoreflect.ValueOfBool(true)
7+
var kindToGenerator = map[protoreflect.Kind]func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value{
8+
protoreflect.BoolKind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
9+
v := protoreflect.ValueOfBool(Bool(fd, opts))
1010
return &v
1111
},
12-
protoreflect.EnumKind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
13-
v := protoreflect.ValueOfEnum(Enum(fd))
12+
protoreflect.EnumKind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
13+
v := protoreflect.ValueOfEnum(Enum(fd, opts))
1414
return &v
1515
},
16-
protoreflect.StringKind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
17-
v := protoreflect.ValueOfString(String(fd))
16+
protoreflect.StringKind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
17+
v := protoreflect.ValueOfString(String(fd, opts))
1818
return &v
1919
},
20-
protoreflect.BytesKind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
21-
v := protoreflect.ValueOfBytes(Bytes(fd))
20+
protoreflect.BytesKind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
21+
v := protoreflect.ValueOfBytes(Bytes(fd, opts))
2222
return &v
2323
},
24-
protoreflect.Int32Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
25-
v := protoreflect.ValueOfInt32(Int32(fd))
24+
protoreflect.Int32Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
25+
v := protoreflect.ValueOfInt32(Int32(fd, opts))
2626
return &v
2727
},
28-
protoreflect.Sint32Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
29-
v := protoreflect.ValueOfInt32(SInt32(fd))
28+
protoreflect.Sint32Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
29+
v := protoreflect.ValueOfInt32(SInt32(fd, opts))
3030
return &v
3131
},
32-
protoreflect.Sfixed32Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
33-
v := protoreflect.ValueOfInt32(SFixed32(fd))
32+
protoreflect.Sfixed32Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
33+
v := protoreflect.ValueOfInt32(SFixed32(fd, opts))
3434
return &v
3535
},
36-
protoreflect.Uint32Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
37-
v := protoreflect.ValueOfUint32(UInt32(fd))
36+
protoreflect.Uint32Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
37+
v := protoreflect.ValueOfUint32(UInt32(fd, opts))
3838
return &v
3939
},
40-
protoreflect.Fixed32Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
41-
v := protoreflect.ValueOfUint32(Fixed32(fd))
40+
protoreflect.Fixed32Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
41+
v := protoreflect.ValueOfUint32(Fixed32(fd, opts))
4242
return &v
4343
},
44-
protoreflect.Int64Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
45-
v := protoreflect.ValueOfInt64(Int64(fd))
44+
protoreflect.Int64Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
45+
v := protoreflect.ValueOfInt64(Int64(fd, opts))
4646
return &v
4747
},
48-
protoreflect.Sint64Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
49-
v := protoreflect.ValueOfInt64(SInt64(fd))
48+
protoreflect.Sint64Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
49+
v := protoreflect.ValueOfInt64(SInt64(fd, opts))
5050
return &v
5151
},
52-
protoreflect.Sfixed64Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
53-
v := protoreflect.ValueOfInt64(SFixed64(fd))
52+
protoreflect.Sfixed64Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
53+
v := protoreflect.ValueOfInt64(SFixed64(fd, opts))
5454
return &v
5555
},
56-
protoreflect.Uint64Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
57-
v := protoreflect.ValueOfUint64(UInt64(fd))
56+
protoreflect.Uint64Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
57+
v := protoreflect.ValueOfUint64(UInt64(fd, opts))
5858
return &v
5959
},
60-
protoreflect.Fixed64Kind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
61-
v := protoreflect.ValueOfUint64(Fixed64(fd))
60+
protoreflect.Fixed64Kind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
61+
v := protoreflect.ValueOfUint64(Fixed64(fd, opts))
6262
return &v
6363
},
64-
protoreflect.FloatKind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
65-
v := protoreflect.ValueOfFloat32(Float32(fd))
64+
protoreflect.FloatKind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
65+
v := protoreflect.ValueOfFloat32(Float32(fd, opts))
6666
return &v
6767
},
68-
protoreflect.DoubleKind: func(fd protoreflect.FieldDescriptor) *protoreflect.Value {
69-
v := protoreflect.ValueOfFloat64(Float64(fd))
68+
protoreflect.DoubleKind: func(fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
69+
v := protoreflect.ValueOfFloat64(Float64(fd, opts))
7070
return &v
7171
},
7272
}
@@ -109,5 +109,5 @@ func getFieldValue(fd protoreflect.FieldDescriptor, opts GenOptions) *protorefle
109109
if !ok {
110110
return nil
111111
}
112-
return fn(fd)
112+
return fn(fd, opts)
113113
}

gen_float.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
)
1010

1111
// Float32 returns a fake float32 value given a field descriptor.
12-
func Float32(fd protoreflect.FieldDescriptor) float32 {
13-
constraints := getResolver().ResolveFieldConstraints(fd)
12+
func Float32(fd protoreflect.FieldDescriptor, opts GenOptions) float32 {
13+
constraints := getFieldConstraints(fd, opts)
1414
if constraints == nil {
1515
return gofakeit.Float32()
1616
}
@@ -48,8 +48,8 @@ func Float32(fd protoreflect.FieldDescriptor) float32 {
4848
}
4949

5050
// Float64 returns a fake float64 value given a field descriptor.
51-
func Float64(fd protoreflect.FieldDescriptor) float64 {
52-
constraints := getResolver().ResolveFieldConstraints(fd)
51+
func Float64(fd protoreflect.FieldDescriptor, opts GenOptions) float64 {
52+
constraints := getFieldConstraints(fd, opts)
5353
if constraints == nil {
5454
return gofakeit.Float64()
5555
}

gen_int.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
)
1010

1111
// Int32 returns a fake int32 value given a field descriptor.
12-
func Int32(fd protoreflect.FieldDescriptor) int32 {
13-
constraints := getResolver().ResolveFieldConstraints(fd)
12+
func Int32(fd protoreflect.FieldDescriptor, opts GenOptions) int32 {
13+
constraints := getFieldConstraints(fd, opts)
1414
if constraints == nil {
1515
return gofakeit.Int32()
1616
}
@@ -48,8 +48,8 @@ func Int32(fd protoreflect.FieldDescriptor) int32 {
4848
}
4949

5050
// Int64 returns a fake int64 value given a field descriptor.
51-
func Int64(fd protoreflect.FieldDescriptor) int64 {
52-
constraints := getResolver().ResolveFieldConstraints(fd)
51+
func Int64(fd protoreflect.FieldDescriptor, opts GenOptions) int64 {
52+
constraints := getFieldConstraints(fd, opts)
5353
if constraints == nil {
5454
return gofakeit.Int64()
5555
}
@@ -87,8 +87,8 @@ func Int64(fd protoreflect.FieldDescriptor) int64 {
8787
}
8888

8989
// SInt32 returns a fake sint32 value given a field descriptor.
90-
func SInt32(fd protoreflect.FieldDescriptor) int32 {
91-
constraints := getResolver().ResolveFieldConstraints(fd)
90+
func SInt32(fd protoreflect.FieldDescriptor, opts GenOptions) int32 {
91+
constraints := getFieldConstraints(fd, opts)
9292
if constraints == nil {
9393
return gofakeit.Int32()
9494
}
@@ -126,8 +126,8 @@ func SInt32(fd protoreflect.FieldDescriptor) int32 {
126126
}
127127

128128
// SInt64 returns a fake sint64 value given a field descriptor.
129-
func SInt64(fd protoreflect.FieldDescriptor) int64 {
130-
constraints := getResolver().ResolveFieldConstraints(fd)
129+
func SInt64(fd protoreflect.FieldDescriptor, opts GenOptions) int64 {
130+
constraints := getFieldConstraints(fd, opts)
131131
if constraints == nil {
132132
return gofakeit.Int64()
133133
}
@@ -165,8 +165,8 @@ func SInt64(fd protoreflect.FieldDescriptor) int64 {
165165
}
166166

167167
// SFixed32 returns a fake sfixedint32 value given a field descriptor.
168-
func SFixed32(fd protoreflect.FieldDescriptor) int32 {
169-
constraints := getResolver().ResolveFieldConstraints(fd)
168+
func SFixed32(fd protoreflect.FieldDescriptor, opts GenOptions) int32 {
169+
constraints := getFieldConstraints(fd, opts)
170170
if constraints == nil {
171171
return gofakeit.Int32()
172172
}
@@ -204,8 +204,8 @@ func SFixed32(fd protoreflect.FieldDescriptor) int32 {
204204
}
205205

206206
// SFixed64 returns a fake sfixed64 value given a field descriptor.
207-
func SFixed64(fd protoreflect.FieldDescriptor) int64 {
208-
constraints := getResolver().ResolveFieldConstraints(fd)
207+
func SFixed64(fd protoreflect.FieldDescriptor, opts GenOptions) int64 {
208+
constraints := getFieldConstraints(fd, opts)
209209
if constraints == nil {
210210
return gofakeit.Int64()
211211
}

gen_map.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package fauxrpc
2+
3+
import (
4+
"fmt"
5+
"log/slog"
6+
7+
"github.com/brianvoe/gofakeit/v7"
8+
"google.golang.org/protobuf/reflect/protoreflect"
9+
)
10+
11+
func mapSimple(msg protoreflect.Message, fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
12+
mapVal := msg.NewField(fd)
13+
itemCount := gofakeit.IntRange(0, 4)
14+
for i := 0; i < itemCount; i++ {
15+
v := getFieldValue(fd.MapKey(), opts.nested())
16+
w := getFieldValue(fd.MapValue(), opts.nested())
17+
if v != nil && w != nil {
18+
mapVal.Map().Set((*v).MapKey(), *w)
19+
} else {
20+
slog.Warn(fmt.Sprintf("Unknown map k/v %s %v", fd.FullName(), fd.Kind()))
21+
}
22+
}
23+
return &mapVal
24+
}
25+
26+
// Map returns a fake repeated value given a field descriptor.
27+
func Map(msg protoreflect.Message, fd protoreflect.FieldDescriptor, opts GenOptions) *protoreflect.Value {
28+
constraints := getResolver().ResolveFieldConstraints(fd)
29+
if constraints == nil {
30+
return mapSimple(msg, fd, opts)
31+
}
32+
rules := constraints.GetEnum()
33+
if rules == nil {
34+
return mapSimple(msg, fd, opts)
35+
}
36+
min, max := uint64(0), uint64(4)
37+
if constraints.GetMap().MinPairs != nil {
38+
min = constraints.GetMap().GetMinPairs()
39+
}
40+
if constraints.GetMap().MaxPairs != nil {
41+
max = constraints.GetMap().GetMaxPairs()
42+
}
43+
44+
mapVal := msg.NewField(fd)
45+
itemCount := gofakeit.IntRange(int(min), int(max))
46+
for i := 0; i < itemCount; i++ {
47+
v := getFieldValue(fd.MapKey(), opts.nested().withExtraFieldConstraints(constraints.GetMap().Keys))
48+
w := getFieldValue(fd.MapValue(), opts.nested().withExtraFieldConstraints(constraints.GetMap().Values))
49+
if v != nil && w != nil {
50+
mapVal.Map().Set((*v).MapKey(), *w)
51+
} else {
52+
slog.Warn(fmt.Sprintf("Unknown map k/v %s %v", fd.FullName(), fd.Kind()))
53+
}
54+
}
55+
return &mapVal
56+
}

gen_msg.go

+4-24
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package fauxrpc
22

33
import (
4-
"fmt"
5-
"log/slog"
6-
74
"github.com/brianvoe/gofakeit/v7"
85
"google.golang.org/protobuf/reflect/protoreflect"
96
)
@@ -78,32 +75,15 @@ func setDataOnMessage(pm protoreflect.ProtoMessage, opts GenOptions) {
7875
continue
7976
}
8077
if field.IsList() {
81-
listVal := msg.NewField(field)
82-
itemCount := gofakeit.IntRange(0, 4)
83-
for i := 0; i < itemCount; i++ {
84-
if v := getFieldValue(field, opts.nested()); v != nil {
85-
listVal.List().Append(*v)
86-
} else {
87-
slog.Warn(fmt.Sprintf("Unknown list value %s %v", field.FullName(), field.Kind()))
88-
}
78+
if val := Repeated(msg, field, opts); val != nil {
79+
msg.Set(field, *val)
8980
}
90-
91-
msg.Set(field, listVal)
9281
return
9382
}
9483
if field.IsMap() {
95-
mapVal := msg.NewField(field)
96-
itemCount := gofakeit.IntRange(0, 4)
97-
for i := 0; i < itemCount; i++ {
98-
v := getFieldValue(field.MapKey(), opts.nested())
99-
w := getFieldValue(field.MapValue(), opts.nested())
100-
if v != nil && w != nil {
101-
mapVal.Map().Set((*v).MapKey(), *w)
102-
} else {
103-
slog.Warn(fmt.Sprintf("Unknown map k/v %s %v", field.FullName(), field.Kind()))
104-
}
84+
if val := Map(msg, field, opts); val != nil {
85+
msg.Set(field, *val)
10586
}
106-
msg.Set(field, mapVal)
10787
return
10888
}
10989
if v := getFieldValue(field, opts.nested()); v != nil {

0 commit comments

Comments
 (0)