Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
rodaine committed May 16, 2024
1 parent 3b1c4f0 commit 5904377
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 18 deletions.
92 changes: 75 additions & 17 deletions internal/cmd/protovalidate-conformance-go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import (
"io"
"log"
"os"
"strings"

"github.com/bufbuild/protovalidate-go"
"github.com/bufbuild/protovalidate-go/internal/gen/buf/validate/conformance/harness"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
"google.golang.org/protobuf/types/dynamicpb"
"google.golang.org/protobuf/types/known/anypb"
)
Expand All @@ -52,10 +52,33 @@ func main() {
}
}

func buildResolver(fdset *descriptorpb.FileDescriptorSet) (*dynResolver, error) {
opts := protodesc.FileOptions{}
res := &protoregistry.Files{}

for _, file := range fdset.GetFile() {
if fdesc, err := opts.New(file, res); err != nil {
return nil, fmt.Errorf("unable to create file descriptor for %v: %v", file.GetName(), err)
} else if err = res.RegisterFile(fdesc); err != nil {
return nil, fmt.Errorf("unable to register file descriptor for %v: %v", file.GetName(), err)
}
}

resolver := dynamicpb.NewTypes(res)
return &dynResolver{
seen: map[protoreflect.FullName]struct{}{},
resolver: resolver,
opts: proto.UnmarshalOptions{
Merge: true,
AllowPartial: true,
Resolver: resolver,
},
}, nil
}

func TestConformance(req *harness.TestConformanceRequest) (*harness.TestConformanceResponse, error) {
files, err := protodesc.NewFiles(req.GetFdset())
resolver, err := buildResolver(req.GetFdset())
if err != nil {
err = fmt.Errorf("failed to parse file descriptors: %w", err)
return nil, err
}
val, err := protovalidate.New()
Expand All @@ -65,25 +88,14 @@ func TestConformance(req *harness.TestConformanceRequest) (*harness.TestConforma
}
resp := &harness.TestConformanceResponse{Results: map[string]*harness.TestResult{}}
for caseName, testCase := range req.GetCases() {
resp.Results[caseName] = TestCase(val, files, testCase)
resp.Results[caseName] = TestCase(val, resolver, testCase)
}
return resp, nil
}

func TestCase(val *protovalidate.Validator, files *protoregistry.Files, testCase *anypb.Any) *harness.TestResult {
urlParts := strings.Split(testCase.GetTypeUrl(), "/")
fullName := protoreflect.FullName(urlParts[len(urlParts)-1])
desc, err := files.FindDescriptorByName(fullName)
func TestCase(val *protovalidate.Validator, resolver *dynResolver, testCase *anypb.Any) *harness.TestResult {
dyn, err := resolver.UnmarshalNew(testCase)
if err != nil {
return unexpectedErrorResult("unable to find descriptor: %v", err)
}
msgDesc, ok := desc.(protoreflect.MessageDescriptor)
if !ok {
return unexpectedErrorResult("expected message descriptor, got %T", desc)
}

dyn := dynamicpb.NewMessage(msgDesc)
if err = anypb.UnmarshalTo(testCase, dyn, proto.UnmarshalOptions{}); err != nil {
return unexpectedErrorResult("unable to unmarshal test case: %v", err)
}

Expand Down Expand Up @@ -126,3 +138,49 @@ func unexpectedErrorResult(format string, args ...any) *harness.TestResult {
},
}
}

type dynResolver struct {
seen map[protoreflect.FullName]struct{}
resolver *dynamicpb.Types
opts proto.UnmarshalOptions
}

func (dr *dynResolver) UnmarshalNew(msg *anypb.Any) (proto.Message, error) {
msgTyp, err := dr.resolver.FindMessageByURL(msg.GetTypeUrl())
if err != nil {
return nil, fmt.Errorf("unable to find message type: %v", err)
} else if err = dr.mergeMsgOpts(msgTyp.Descriptor()); err != nil {
return nil, err
}
dyn := msgTyp.New().Interface()
return dyn, anypb.UnmarshalTo(msg, dyn, dr.opts)
}

func (dr *dynResolver) mergeOpts(desc protoreflect.Descriptor) error {
return dr.opts.Unmarshal(desc.Options().ProtoReflect().GetUnknown(), desc.Options())
}

func (dr *dynResolver) mergeMsgOpts(mDesc protoreflect.MessageDescriptor) error {
if _, seen := dr.seen[mDesc.FullName()]; seen {
return nil
}
dr.seen[mDesc.FullName()] = struct{}{}
if err := dr.mergeOpts(mDesc); err != nil {
return fmt.Errorf("failed to merge options for %v: %w", mDesc.FullName(), err)
}

fields := mDesc.Fields()
for i, n := 0, fields.Len(); i < n; i++ {
field := fields.Get(i)
if err := dr.mergeOpts(field); err != nil {
return fmt.Errorf("failed to merge options for %v: %w", field.FullName(), err)
}
if field.Kind() == protoreflect.MessageKind {
if err := dr.mergeMsgOpts(field.Message()); err != nil {
return err
}
}
}

return nil
}
21 changes: 21 additions & 0 deletions internal/evaluator/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package evaluator

import (
"log"
"sync"
"sync/atomic"

Expand All @@ -24,6 +25,7 @@ import (
"github.com/bufbuild/protovalidate-go/internal/errors"
"github.com/bufbuild/protovalidate-go/internal/expression"
"github.com/google/cel-go/cel"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/dynamicpb"
)
Expand Down Expand Up @@ -241,6 +243,7 @@ func (bldr *Builder) buildValue(
bldr.processEnumConstraints,
bldr.processMapConstraints,
bldr.processRepeatedConstraints,
bldr.processSharedConstraints,
}

for _, step := range steps {
Expand All @@ -251,6 +254,24 @@ func (bldr *Builder) buildValue(
return nil
}

func (bldr *Builder) processSharedConstraints(
fdesc protoreflect.FieldDescriptor,
_ *validate.FieldConstraints,
forItems bool,
valEval *value,
_ MessageCache,
) error {
if forItems {
return nil
}
proto.RangeExtensions(fdesc.Options(), func(extTyp protoreflect.ExtensionType, rules interface{}) bool {
if extTyp.TypeDescriptor().Kind()
log.Println(extTyp.TypeDescriptor().FullName(), rules)
return true
})
return nil
}

func (bldr *Builder) processIgnoreEmpty(
fdesc protoreflect.FieldDescriptor,
constraints *validate.FieldConstraints,
Expand Down
2 changes: 1 addition & 1 deletion proto/tests/example/v1/validations.proto
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,4 @@ message RepeatedItemCel {
id: "paths.no_space",
expression: "!this.startsWith(' ')"
}];
}
}

0 comments on commit 5904377

Please sign in to comment.