├── .gitattributes ├── .gitignore ├── internal ├── testdata │ ├── errors.proto3test.yaml │ ├── validate.validate.yaml │ ├── ext.proto2test.yaml │ ├── ext.proto2test.txt │ ├── errors.proto3test.txt │ ├── validate.validate.txt │ ├── basic.valid.proto3test.txt │ ├── basic.valid.proto3test.yaml │ ├── basic.proto3test.yaml │ ├── dynamic.const.yaml │ ├── dynamic.const.txt │ └── basic.proto3test.txt ├── proto │ ├── buf │ │ └── protoyaml │ │ │ └── test │ │ │ └── v1 │ │ │ ├── pb3.proto │ │ │ ├── const.proto │ │ │ ├── pb2.proto │ │ │ ├── editions.proto │ │ │ └── validate.proto │ └── bufext │ │ └── cel │ │ └── expr │ │ └── conformance │ │ └── proto3 │ │ └── test_all_types.proto ├── protoyamltest │ ├── golden │ │ ├── golden_test.go │ │ └── golden.go │ ├── fuzz.go │ └── combine.go ├── cmd │ └── generate-txt-testdata │ │ └── main.go └── gen │ └── proto │ └── buf │ └── protoyaml │ └── test │ └── v1 │ ├── pb3.pb.go │ ├── const.pb.go │ ├── validate.pb.go │ ├── pb2.pb.go │ └── editions.pb.go ├── .github ├── dependabot.yml ├── release.yml ├── workflows │ ├── notify-approval-bypass.yaml │ ├── emergency-review-bypass.yaml │ ├── add-to-project.yaml │ ├── pr-title.yaml │ └── ci.yaml └── CODE_OF_CONDUCT.md ├── buf.yaml ├── buf.lock ├── buf.gen.yaml ├── go.mod ├── errors.go ├── .golangci.yml ├── Makefile ├── encode.go ├── go.sum ├── README.md ├── encode_test.go ├── decode_test.go ├── LICENSE └── protoyaml_test.go /.gitattributes: -------------------------------------------------------------------------------- 1 | internal/gen/**/* linguist-generated=true 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /.tmp/ 3 | /internal/cmd/generate-txt-testdata/generate-txt-testdata 4 | -------------------------------------------------------------------------------- /internal/testdata/errors.proto3test.yaml: -------------------------------------------------------------------------------- 1 | # Structural errors 2 | bad: wat 3 | 1: 2 4 | -1: 3 5 | [1, 2]: 2 6 | values: 7 | - wat: 1 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /buf.yaml: -------------------------------------------------------------------------------- 1 | version: v2 2 | modules: 3 | - path: internal/proto 4 | deps: 5 | - buf.build/bufbuild/protovalidate 6 | lint: 7 | except: 8 | - FIELD_NOT_REQUIRED 9 | ignore: 10 | - internal/proto/bufext 11 | -------------------------------------------------------------------------------- /buf.lock: -------------------------------------------------------------------------------- 1 | # Generated by buf. DO NOT EDIT. 2 | version: v2 3 | deps: 4 | - name: buf.build/bufbuild/protovalidate 5 | commit: 7712fb530c574b95bc1d57c0877543c3 6 | digest: b5:b3e9c9428384357e3b73e4d5a4614328b0a4b1595b10163bbe9483fa16204749274c41797bd49b0d716479c855aa35c1172a94f471fa120ba8369637fd138829 7 | -------------------------------------------------------------------------------- /internal/testdata/validate.validate.yaml: -------------------------------------------------------------------------------- 1 | cases: 2 | - float_gt_lt: 0 3 | - float_gt_lt: 10 4 | - float_gt_lt: 10.5 5 | - float_gt_lt: -0.5 6 | - floatGtLt: 10.5 7 | - 2: -Infinity 8 | # - float_gt_lt: NaN 9 | - float_gt_lt: 1 10 | string_map: 11 | c1: B 12 | - string_map: 13 | b: B1 14 | -------------------------------------------------------------------------------- /internal/testdata/ext.proto2test.yaml: -------------------------------------------------------------------------------- 1 | '[undefined]': hi 2 | '[buf.protoyaml.test.v1.p2t_string_ext]': hi 3 | [buf.protoyaml.test.v1.p2t_repeated_string_ext]: [hi] 4 | [buf.protoyaml.test.v1.p2t_repeated_string_ext, hi]: [hi] 5 | values: 6 | - oneof_string_value: hi 7 | - oneof_int32_value: 1 8 | - oneof_string_value: hi 9 | oneof_int32_value: 1 10 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - ignore-for-release 5 | authors: 6 | - dependabot 7 | categories: 8 | - title: Enhancements 9 | labels: 10 | - enhancement 11 | - title: Bugfixes 12 | labels: 13 | - bug 14 | - title: Other changes 15 | labels: 16 | - "*" 17 | -------------------------------------------------------------------------------- /.github/workflows/notify-approval-bypass.yaml: -------------------------------------------------------------------------------- 1 | name: PR Approval Bypass Notifier 2 | on: 3 | pull_request: 4 | types: 5 | - closed 6 | branches: 7 | - main 8 | permissions: 9 | pull-requests: read 10 | jobs: 11 | approval: 12 | uses: bufbuild/base-workflows/.github/workflows/notify-approval-bypass.yaml@main 13 | secrets: inherit 14 | -------------------------------------------------------------------------------- /.github/workflows/emergency-review-bypass.yaml: -------------------------------------------------------------------------------- 1 | name: Bypass review in case of emergency 2 | on: 3 | pull_request: 4 | types: 5 | - labeled 6 | permissions: 7 | pull-requests: write 8 | jobs: 9 | approve: 10 | if: github.event.label.name == 'Emergency Bypass Review' 11 | uses: bufbuild/base-workflows/.github/workflows/emergency-review-bypass.yaml@main 12 | secrets: inherit 13 | -------------------------------------------------------------------------------- /buf.gen.yaml: -------------------------------------------------------------------------------- 1 | version: v2 2 | managed: 3 | enabled: true 4 | disable: 5 | - file_option: go_package 6 | module: buf.build/bufbuild/protovalidate 7 | override: 8 | - file_option: go_package_prefix 9 | value: buf.build/go/protoyaml/internal/gen/proto 10 | plugins: 11 | - remote: buf.build/protocolbuffers/go:v1.36.6 12 | out: internal/gen/proto 13 | opt: paths=source_relative 14 | -------------------------------------------------------------------------------- /internal/testdata/ext.proto2test.txt: -------------------------------------------------------------------------------- 1 | internal/testdata/ext.proto2test.yaml:1:1 unknown field "[undefined]", expected one of [values] 2 | 1 | '[undefined]': hi 3 | 1 | ^ 4 | 5 | internal/testdata/ext.proto2test.yaml:4:1 expected scalar, got sequence 6 | 4 | [buf.protoyaml.test.v1.p2t_repeated_string_ext, hi]: [hi] 7 | 4 | ^ 8 | 9 | internal/testdata/ext.proto2test.yaml:9:24 field oneof_string_value is already set for oneof oneof_value 10 | 9 | oneof_int32_value: 1 11 | 9 | .......................^ 12 | -------------------------------------------------------------------------------- /.github/workflows/add-to-project.yaml: -------------------------------------------------------------------------------- 1 | name: Add issues and PRs to project 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - reopened 8 | - transferred 9 | pull_request_target: 10 | types: 11 | - opened 12 | - reopened 13 | issue_comment: 14 | types: 15 | - created 16 | 17 | jobs: 18 | call-workflow-add-to-project: 19 | name: Call workflow to add issue to project 20 | uses: bufbuild/base-workflows/.github/workflows/add-to-project.yaml@main 21 | secrets: inherit 22 | -------------------------------------------------------------------------------- /.github/workflows/pr-title.yaml: -------------------------------------------------------------------------------- 1 | name: Lint PR Title 2 | # Prevent writing to the repository using the CI token. 3 | # Ref: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#permissions 4 | permissions: 5 | pull-requests: read 6 | on: 7 | pull_request: 8 | # By default, a workflow only runs when a pull_request's activity type is opened, 9 | # synchronize, or reopened. We explicity override here so that PR titles are 10 | # re-linted when the PR text content is edited. 11 | types: 12 | - opened 13 | - edited 14 | - reopened 15 | - synchronize 16 | jobs: 17 | lint: 18 | uses: bufbuild/base-workflows/.github/workflows/pr-title.yaml@main 19 | -------------------------------------------------------------------------------- /internal/testdata/errors.proto3test.txt: -------------------------------------------------------------------------------- 1 | internal/testdata/errors.proto3test.yaml:2:1 unknown field "bad", expected one of [values] 2 | 2 | bad: wat 3 | 2 | ^ 4 | 5 | internal/testdata/errors.proto3test.yaml:3:4 expected sequence, got scalar 6 | 3 | 1: 2 7 | 3 | ...^ 8 | 9 | internal/testdata/errors.proto3test.yaml:4:1 unknown field "-1", expected one of [values] 10 | 4 | -1: 3 11 | 4 | ^ 12 | 13 | internal/testdata/errors.proto3test.yaml:5:1 expected scalar, got sequence 14 | 5 | [1, 2]: 2 15 | 5 | ^ 16 | 17 | internal/testdata/errors.proto3test.yaml:7:5 unknown field "wat", expected one of [single_int32 single_int64 single_uint32 single_uint64 single_sint32 single_sint64 single_fixed32 ...] 18 | 7 | - wat: 1 19 | 7 | ....^ 20 | -------------------------------------------------------------------------------- /internal/proto/buf/protoyaml/test/v1/pb3.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package buf.protoyaml.test.v1; 18 | 19 | import "bufext/cel/expr/conformance/proto3/test_all_types.proto"; 20 | 21 | message Proto3Test { 22 | repeated bufext.cel.expr.conformance.proto3.TestAllTypes values = 1; 23 | } 24 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module buf.build/go/protoyaml 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250425153114-8976f5be98c1.1 7 | buf.build/go/protovalidate v0.11.0 8 | github.com/google/go-cmp v0.7.0 9 | github.com/stretchr/testify v1.10.0 10 | google.golang.org/protobuf v1.36.6 11 | gopkg.in/yaml.v3 v3.0.1 12 | ) 13 | 14 | require ( 15 | cel.dev/expr v0.23.1 // indirect 16 | github.com/antlr4-go/antlr/v4 v4.13.0 // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/google/cel-go v0.25.0 // indirect 19 | github.com/pmezard/go-difflib v1.0.0 // indirect 20 | github.com/stoewer/go-strcase v1.3.0 // indirect 21 | golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect 22 | golang.org/x/text v0.23.0 // indirect 23 | google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect 24 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect 25 | ) 26 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: [main] 5 | tags: ['v*'] 6 | pull_request: 7 | branches: [main] 8 | schedule: 9 | - cron: '15 22 * * *' 10 | workflow_dispatch: {} # support manual runs 11 | permissions: 12 | contents: read 13 | jobs: 14 | ci: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | go-version: [1.23.x, 1.24.x] 19 | steps: 20 | - name: Checkout Code 21 | uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 1 24 | - name: Install Go 25 | uses: actions/setup-go@v5 26 | with: 27 | go-version: ${{ matrix.go-version }} 28 | - name: Test 29 | run: make test 30 | - name: Lint 31 | # Often, lint & gofmt guidelines depend on the Go version. To prevent 32 | # conflicting guidance, run only on the most recent supported version. 33 | # For the same reason, only check generated code on the most recent 34 | # supported version. 35 | if: matrix.go-version == '1.24.x' 36 | run: make checkgenerate && make lint 37 | -------------------------------------------------------------------------------- /internal/proto/buf/protoyaml/test/v1/const.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package buf.protoyaml.test.v1; 18 | 19 | import "google/protobuf/any.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | message ConstValues { 23 | string name = 1; // file name, relative to root of source tree 24 | string package = 2; // e.g. "foo", "foo.bar", etc. 25 | repeated string dependency = 3; 26 | google.protobuf.FileOptions options = 8; 27 | map values = 4; 28 | } 29 | -------------------------------------------------------------------------------- /internal/proto/buf/protoyaml/test/v1/pb2.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto2"; 16 | 17 | package buf.protoyaml.test.v1; 18 | 19 | message Proto2Test { 20 | repeated Proto2TestValue values = 1; 21 | extensions 100 to max; 22 | } 23 | 24 | message Proto2TestValue { 25 | oneof oneof_value { 26 | string oneof_string_value = 1; 27 | int32 oneof_int32_value = 2; 28 | } 29 | } 30 | 31 | extend Proto2Test { 32 | optional string p2t_string_ext = 100; 33 | repeated string p2t_repeated_string_ext = 101; 34 | } 35 | -------------------------------------------------------------------------------- /internal/proto/buf/protoyaml/test/v1/editions.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | edition = "2023"; 16 | 17 | package buf.protoyaml.test.v1; 18 | 19 | message EditionsTest { 20 | string name = 1 [features.field_presence = LEGACY_REQUIRED]; 21 | Nested nested = 2 [features.message_encoding = DELIMITED]; 22 | message Nested { 23 | repeated int64 ids = 1 [features.repeated_field_encoding = EXPANDED]; 24 | } 25 | OpenEnum enum = 3 [features.field_presence = IMPLICIT]; 26 | } 27 | 28 | enum OpenEnum { 29 | OPEN_ENUM_UNSPECIFIED = 0; 30 | } 31 | 32 | enum ClosedEnum { 33 | option features.enum_type = CLOSED; 34 | CLOSED_ENUM_UNSPECIFIED = 0; 35 | } 36 | -------------------------------------------------------------------------------- /internal/proto/buf/protoyaml/test/v1/validate.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package buf.protoyaml.test.v1; 18 | 19 | import "buf/validate/validate.proto"; 20 | import "google/protobuf/any.proto"; 21 | 22 | message ValidateTest { 23 | repeated ValidateTestCase cases = 1; 24 | } 25 | 26 | message ValidateTestCase { 27 | google.protobuf.Any dynamic = 1; 28 | float float_gt_lt = 2 [(buf.validate.field).float = { 29 | gt: 0 30 | lt: 10 31 | }]; 32 | map string_map = 3 [(buf.validate.field).map = { 33 | keys: { 34 | string: {pattern: "^[a-z]+$"} 35 | } 36 | values: { 37 | string: {pattern: "^[A-Z]+$"} 38 | } 39 | }]; 40 | } 41 | -------------------------------------------------------------------------------- /internal/testdata/validate.validate.txt: -------------------------------------------------------------------------------- 1 | internal/testdata/validate.validate.yaml:2:18 cases[0].float_gt_lt: value must be greater than 0 and less than 10 (float.gt_lt) 2 | 2 | - float_gt_lt: 0 3 | 2 | .................^ 4 | 5 | internal/testdata/validate.validate.yaml:3:18 cases[1].float_gt_lt: value must be greater than 0 and less than 10 (float.gt_lt) 6 | 3 | - float_gt_lt: 10 7 | 3 | .................^ 8 | 9 | internal/testdata/validate.validate.yaml:4:18 cases[2].float_gt_lt: value must be greater than 0 and less than 10 (float.gt_lt) 10 | 4 | - float_gt_lt: 10.5 11 | 4 | .................^ 12 | 13 | internal/testdata/validate.validate.yaml:5:18 cases[3].float_gt_lt: value must be greater than 0 and less than 10 (float.gt_lt) 14 | 5 | - float_gt_lt: -0.5 15 | 5 | .................^ 16 | 17 | internal/testdata/validate.validate.yaml:6:16 cases[4].float_gt_lt: value must be greater than 0 and less than 10 (float.gt_lt) 18 | 6 | - floatGtLt: 10.5 19 | 6 | ...............^ 20 | 21 | internal/testdata/validate.validate.yaml:7:8 cases[5].float_gt_lt: value must be greater than 0 and less than 10 (float.gt_lt) 22 | 7 | - 2: -Infinity 23 | 7 | .......^ 24 | 25 | internal/testdata/validate.validate.yaml:11:7 cases[6].string_map["c1"]: value does not match regex pattern `^[a-z]+$` (string.pattern) 26 | 11 | c1: B 27 | 11 | ......^ 28 | 29 | internal/testdata/validate.validate.yaml:12:5 cases[7].float_gt_lt: value must be greater than 0 and less than 10 (float.gt_lt) 30 | 12 | - string_map: 31 | 12 | ....^ 32 | 33 | internal/testdata/validate.validate.yaml:13:10 cases[7].string_map["b"]: value does not match regex pattern `^[A-Z]+$` (string.pattern) 34 | 13 | b: B1 35 | 13 | .........^ 36 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protoyaml 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | 21 | "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate" 22 | "buf.build/go/protovalidate" 23 | "gopkg.in/yaml.v3" 24 | ) 25 | 26 | // nodeError is an error that occurred while processing a specific yaml.Node. 27 | type nodeError struct { 28 | Node *yaml.Node 29 | Path string 30 | line string 31 | cause error 32 | } 33 | 34 | func (n *nodeError) Unwrap() error { 35 | return n.cause 36 | } 37 | 38 | // DetailedError returns an error message that includes the path and a code snippet, if 39 | // the lines of the source code are provided. 40 | func (n *nodeError) Error() string { 41 | var result strings.Builder 42 | result.WriteString(fmt.Sprintf("%s:%d:%d %s\n", n.Path, n.Node.Line, n.Node.Column, n.Unwrap().Error())) 43 | if n.line != "" { 44 | lineNum := fmt.Sprintf("%4d", n.Node.Line) 45 | result.WriteString(fmt.Sprintf("%s | %s\n", lineNum, n.line)) 46 | marker := strings.Repeat(".", n.Node.Column-1) + "^" 47 | result.WriteString(fmt.Sprintf("%s | %s\n", lineNum, marker)) 48 | } 49 | return result.String() 50 | } 51 | 52 | // violationError is singe validation violation. 53 | type violationError struct { 54 | Violation *validate.Violation 55 | } 56 | 57 | // Error prints the field path, message, and constraint ID. 58 | func (v *violationError) Error() string { 59 | return protovalidate.FieldPathString(v.Violation.GetField()) + ": " + v.Violation.GetMessage() + " (" + v.Violation.GetRuleId() + ")" 60 | } 61 | -------------------------------------------------------------------------------- /internal/protoyamltest/golden/golden_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package golden 16 | 17 | import ( 18 | "io" 19 | "io/fs" 20 | "os" 21 | "strings" 22 | "testing" 23 | 24 | "github.com/google/go-cmp/cmp" 25 | "github.com/stretchr/testify/require" 26 | ) 27 | 28 | func TestGoldenFiles(t *testing.T) { 29 | t.Parallel() 30 | // Walk the test data directory for .yaml files 31 | fsys := os.DirFS("../../..") 32 | if err := fs.WalkDir(fsys, "internal/testdata", func(path string, info fs.DirEntry, err error) error { 33 | if err != nil { 34 | return err 35 | } 36 | if !info.IsDir() && strings.HasSuffix(path, ".yaml") { 37 | t.Run(path, func(t *testing.T) { 38 | t.Parallel() 39 | testRunYAMLFile(t, fsys, path) 40 | }) 41 | } 42 | return nil 43 | }); err != nil { 44 | t.Fatal(err) 45 | } 46 | } 47 | 48 | func testRunYAMLFile(t *testing.T, fsys fs.FS, testFile string) { 49 | t.Helper() 50 | 51 | file, err := fsys.Open(testFile) 52 | require.NoError(t, err) 53 | defer file.Close() 54 | 55 | data, err := io.ReadAll(file) 56 | require.NoError(t, err) 57 | 58 | actualText, err := GenGoldenContent(testFile, data) 59 | require.NoError(t, err) 60 | 61 | // Read the expected file 62 | expectedFileName := strings.TrimSuffix(testFile, ".yaml") + ".txt" 63 | expectedFile, err := fsys.Open(expectedFileName) 64 | var expectedData []byte 65 | if err != nil { 66 | t.Fatal(err) 67 | } else { 68 | defer expectedFile.Close() 69 | expectedData, err = io.ReadAll(expectedFile) 70 | if err != nil { 71 | t.Fatal(err) 72 | } 73 | } 74 | expectedText := string(expectedData) 75 | if expectedText != actualText { 76 | diff := cmp.Diff(expectedText, actualText) 77 | t.Errorf("%s: Test %s failed:\nExpected:\n%s\nActual:\n%s\nDiff:\n%s", expectedFileName, testFile, expectedText, actualText, diff) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /internal/cmd/generate-txt-testdata/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "fmt" 19 | "io" 20 | "os" 21 | "path/filepath" 22 | "strings" 23 | 24 | "buf.build/go/protoyaml/internal/protoyamltest/golden" 25 | ) 26 | 27 | func main() { 28 | if err := run(); err != nil { 29 | if errString := err.Error(); errString != "" { 30 | _, _ = fmt.Fprintln(os.Stderr, errString) 31 | } 32 | os.Exit(1) 33 | } 34 | } 35 | 36 | func run() error { 37 | if len(os.Args) != 2 { 38 | return fmt.Errorf("usage: %s [file or directory]", os.Args[0]) 39 | } 40 | filePath := os.Args[1] 41 | 42 | // If the file is a directory, recurse 43 | fileInfo, err := os.Stat(filePath) 44 | if err != nil { 45 | return err 46 | } 47 | if fileInfo.IsDir() { 48 | return filepath.Walk(filePath, func(path string, info os.FileInfo, err error) error { 49 | if err != nil { 50 | return err 51 | } 52 | if !strings.HasSuffix(path, ".yaml") { 53 | return nil 54 | } 55 | actualText, err := tryParse(path) 56 | if err != nil { 57 | return err 58 | } 59 | // Replace the {type}.yaml extension with .expected.txt 60 | expectedPath := strings.TrimSuffix(path, ".yaml") + ".txt" 61 | // Write the actual text to the expected file 62 | if err := os.WriteFile(expectedPath, []byte(actualText), 0600); err != nil { 63 | return err 64 | } 65 | return nil 66 | }) 67 | } 68 | actualText, err := tryParse(filePath) 69 | if err != nil { 70 | return err 71 | } 72 | fmt.Print(actualText) 73 | return nil 74 | } 75 | 76 | func tryParse(filePath string) (string, error) { 77 | file, err := os.Open(filePath) 78 | if err != nil { 79 | return "", err 80 | } 81 | defer file.Close() 82 | data, err := io.ReadAll(file) 83 | if err != nil { 84 | return "", err 85 | } 86 | return golden.GenGoldenContent(filePath, data) 87 | } 88 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | default: all 4 | disable: 5 | - cyclop # covered by gocyclo 6 | - exhaustive 7 | - exhaustruct 8 | - funlen # rely on code review to limit function length 9 | - gochecknoglobals 10 | - gocognit # dubious "cognitive overhead" quantification 11 | - ireturn # "accept interfaces, return structs" isn't ironclad 12 | - lll # don't want hard limits for line length 13 | - maintidx # covered by gocyclo 14 | - mnd 15 | - nlreturn # generous whitespace violates house style 16 | - nonamedreturns 17 | - testpackage # internal tests are fine 18 | - wrapcheck # don't _always_ need to wrap errors 19 | - wsl # generous whitespace violates house style 20 | settings: 21 | depguard: 22 | rules: 23 | Main: 24 | files: 25 | - $all 26 | - '!$test' 27 | allow: 28 | - $gostd 29 | - github.com/bufbuild/protoyaml-go/decode 30 | - buf.build/gen/go/bufbuild/protovalidate 31 | - buf.build/go/protovalidate 32 | - google.golang.org/protobuf 33 | - gopkg.in/yaml.v3 34 | errcheck: 35 | check-type-assertions: true 36 | forbidigo: 37 | forbid: 38 | - pattern: ^fmt\.Print 39 | - pattern: ^log\. 40 | - pattern: ^print$ 41 | - pattern: ^println$ 42 | - pattern: ^panic$ 43 | gocyclo: 44 | min-complexity: 15 45 | godox: 46 | keywords: 47 | - FIXME 48 | varnamelen: 49 | ignore-decls: 50 | - ok bool 51 | - T any 52 | - i int 53 | - wg sync.WaitGroup 54 | exclusions: 55 | generated: lax 56 | presets: 57 | - comments 58 | - common-false-positives 59 | - legacy 60 | - std-error-handling 61 | rules: 62 | - linters: 63 | - nestif 64 | path: _test.go 65 | - linters: 66 | - depguard 67 | - forbidigo 68 | - revive 69 | path: internal/* 70 | - linters: 71 | - gosec 72 | - gosmopolitan 73 | - prealloc 74 | path: internal/protoyamltest/* 75 | - path: (.+)\.go$ 76 | text: do not define dynamic errors.* 77 | issues: 78 | max-same-issues: 0 79 | formatters: 80 | enable: 81 | - gci 82 | - gofmt 83 | exclusions: 84 | generated: lax 85 | -------------------------------------------------------------------------------- /internal/testdata/basic.valid.proto3test.txt: -------------------------------------------------------------------------------- 1 | values: 2 | - single_int32: 1 3 | single_int64: "1" 4 | single_sint32: 1 5 | single_sint64: "1" 6 | single_sfixed32: 1 7 | single_bool: true 8 | - {} 9 | - single_bool: true 10 | - {} 11 | - {} 12 | - single_sfixed32: 1 13 | - single_sint32: 1 14 | - single_int32: -1 15 | - single_int32: 2147483647 16 | - single_int32: -2147483648 17 | - single_int32: 2147483647 18 | - single_int32: -2147483648 19 | - single_int32: 2147483647 20 | - single_int32: -2147483648 21 | - single_int32: 2147483647 22 | - single_int32: -2147483648 23 | - single_int32: 1 24 | - {} 25 | - single_sint64: "1" 26 | - single_sfixed64: "1" 27 | - single_int64: "9223372036854775807" 28 | - single_int64: "-9223372036854775808" 29 | - single_int64: "9007199254740991" 30 | - {} 31 | - single_fixed32: 1 32 | - single_fixed64: "1" 33 | - single_uint32: 4294967295 34 | - single_uint64: "18446744073709551615" 35 | - single_float: 1 36 | - single_float: 1 37 | - single_float: 10 38 | - single_float: 1.7014118e+38 39 | - single_float: Infinity 40 | - single_float: Infinity 41 | - single_double: -Infinity 42 | - single_double: NaN 43 | - single_double: Infinity 44 | - single_string: "1" 45 | - single_string: "1.0" 46 | - single_string: "true" 47 | - single_string: "false" 48 | - single_string: "null" 49 | - single_string: "null" 50 | - single_string: "1" 51 | - single_string: "\U0001F600" 52 | - single_bytes: good 53 | - single_bytes: GOOD 54 | - single_bytes: Zg== 55 | - standalone_enum: -1 56 | - {} 57 | - standalone_enum: BAR 58 | - standalone_enum: 100 59 | - {} 60 | - repeated_int32: 61 | - 1 62 | - repeated_int32: 63 | - 1 64 | - 1 65 | - standalone_message: {} 66 | - single_duration: 1s 67 | - single_duration: 1.123456789s 68 | - single_duration: 1.000000002s 69 | - single_timestamp: "0001-01-01T00:00:00Z" 70 | - single_timestamp: "9999-12-31T23:59:59.999999999Z" 71 | - single_timestamp: "1970-01-01T00:00:00Z" 72 | - single_timestamp: "1970-01-01T00:00:00Z" 73 | - single_timestamp: "1970-01-01T00:00:00.000000001Z" 74 | - single_timestamp: "1970-01-01T00:00:01.000000002Z" 75 | - single_int32_wrapper: 1 76 | - single_int32_wrapper: 1 77 | - single_bytes: nopadw== 78 | - single_bytes: web+safe/w== 79 | -------------------------------------------------------------------------------- /internal/testdata/basic.valid.proto3test.yaml: -------------------------------------------------------------------------------- 1 | # Constant values to test. 2 | values: 3 | # Encode reorders to match the field order in the proto. 4 | - single_bool: true 5 | single_int32: 1 6 | single_int64: 1 7 | single_sint32: 1 8 | single_sint64: 1 9 | single_sfixed32: 1 10 | - single_bool: false 11 | - 13: true # single_bool has a field number of 13 12 | - singleBool: false # The 'json name' of single_bool is singleBool 13 | - single_int32: 0 14 | - single_sfixed32: 1 15 | - single_sint32: 1.0 16 | - single_int32: -1 17 | - single_int32: 2147483647 18 | - single_int32: -2147483648 19 | - single_int32: 0x7fffffff 20 | - single_int32: -0X80000000 21 | - single_int32: 0o17777777777 22 | - single_int32: -0O20000000000 23 | - single_int32: 0b1111111111111111111111111111111 24 | - single_int32: -0B10000000000000000000000000000000 25 | - single_int32: 1.0 26 | - single_int64: 0 27 | - single_sint64: 1 28 | - single_sfixed64: 1.0 29 | - single_int64: 9223372036854775807 30 | - single_int64: -9223372036854775808 31 | - single_int64: 9007199254740991.0 32 | - single_uint64: 0 33 | - single_fixed32: 1.0 34 | - single_fixed64: 1.0 35 | - single_uint32: 4294967295 36 | - single_uint64: 18446744073709551615 37 | - single_float: 1.0 38 | - single_float: 1 39 | - single_float: 1.0e1 40 | # Maximum representable value in single precision is 2^128 - 2^104 41 | - single_float: 1.7014118346046923e+38 42 | - single_float: INF 43 | - single_float: inf 44 | - single_double: -inf 45 | - single_double: nan 46 | - single_double: Infinity 47 | - single_string: 1 48 | - single_string: 1.0 49 | - single_string: true 50 | - single_string: false 51 | - single_string: null 52 | - single_string: "null" 53 | - single_string: "1" 54 | - single_string: "\U0001F600" 55 | - single_bytes: good 56 | - single_bytes: GOOD 57 | - single_bytes: "Zg==" 58 | - standalone_enum: -1 59 | - standalone_enum: 0 60 | - standalone_enum: 1 61 | - standalone_enum: 100 62 | - standalone_enum: FOO 63 | - repeated_int32: [1] 64 | - repeated_int32: [1, "1"] 65 | - standalone_message: {} 66 | - single_duration: 1s 67 | - single_duration: 1.123456789s 68 | - single_duration: 69 | seconds: 1 70 | nanos: 2 71 | - single_timestamp: 0001-01-01T00:00:00Z 72 | - single_timestamp: 9999-12-31T23:59:59.999999999Z 73 | - single_timestamp: 1970-01-01T00:00:00Z 74 | - single_timestamp: 1970-01-01T00:00:00.000000000Z 75 | - single_timestamp: 1970-01-01T00:00:00.000000001Z 76 | - single_timestamp: 77 | seconds: 1 78 | nanos: 2 79 | - single_int32_wrapper: 1 80 | - single_int32_wrapper: 81 | value: 1 82 | - single_bytes: "nopad+" 83 | - single_bytes: "web-safe__" 84 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # See https://tech.davis-hansson.com/p/make/ 2 | SHELL := bash 3 | .DELETE_ON_ERROR: 4 | .SHELLFLAGS := -eu -o pipefail -c 5 | .DEFAULT_GOAL := all 6 | MAKEFLAGS += --warn-undefined-variables 7 | MAKEFLAGS += --no-builtin-rules 8 | MAKEFLAGS += --no-print-directory 9 | BIN := .tmp/bin 10 | export PATH := $(BIN):$(PATH) 11 | export GOBIN := $(abspath $(BIN)) 12 | COPYRIGHT_YEARS := 2023-2024 13 | LICENSE_IGNORE := --ignore testdata/ 14 | 15 | .PHONY: help 16 | help: ## Describe useful make targets 17 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "%-30s %s\n", $$1, $$2}' 18 | 19 | .PHONY: all 20 | all: ## Build, test, and lint (default) 21 | $(MAKE) test 22 | $(MAKE) lint 23 | 24 | .PHONY: clean 25 | clean: ## Delete intermediate build artifacts 26 | @# -X only removes untracked files, -d recurses into directories, -f actually removes files/dirs 27 | git clean -Xdf 28 | 29 | .PHONY: test 30 | test: build ## Run unit tests 31 | go test -vet=off -race -cover ./... 32 | 33 | .PHONY: build 34 | build: generate ## Build all packages 35 | go build ./... 36 | 37 | .PHONY: lint 38 | lint: $(BIN)/golangci-lint $(BIN)/buf ## Lint 39 | go vet ./... 40 | $(BIN)/golangci-lint fmt --diff 41 | $(BIN)/golangci-lint run 42 | buf lint 43 | buf format -d --exit-code 44 | 45 | .PHONY: lintfix 46 | lintfix: $(BIN)/golangci-lint ## Automatically fix some lint errors 47 | $(BIN)/golangci-lint fmt 48 | $(BIN)/golangci-lint run --fix 49 | buf format -w 50 | 51 | .PHONY: install 52 | install: ## Install all binaries 53 | go install ./... 54 | 55 | .PHONY: generate 56 | generate: $(BIN)/license-header $(BIN)/buf ## Regenerate code and licenses 57 | rm -rf internal/gen 58 | buf generate 59 | license-header \ 60 | --license-type apache \ 61 | --copyright-holder "Buf Technologies, Inc." \ 62 | --year-range "$(COPYRIGHT_YEARS)" $(LICENSE_IGNORE) 63 | 64 | .PHONY: golden 65 | golden: 66 | find internal/testdata -name "*.txt" -type f -delete 67 | go run internal/cmd/generate-txt-testdata/main.go internal/testdata 68 | 69 | .PHONY: upgrade 70 | upgrade: ## Upgrade dependencies 71 | go get -u -t ./... 72 | go mod tidy -v 73 | buf mod update internal/proto 74 | 75 | .PHONY: checkgenerate 76 | checkgenerate: 77 | @# Used in CI to verify that `make generate` doesn't produce a diff. 78 | test -z "$$(git status --porcelain | tee /dev/stderr)" 79 | 80 | $(BIN): 81 | @mkdir -p $(BIN) 82 | 83 | $(BIN)/buf: $(BIN) Makefile 84 | go install github.com/bufbuild/buf/cmd/buf@v1.51.0 85 | 86 | $(BIN)/license-header: $(BIN) Makefile 87 | go install \ 88 | github.com/bufbuild/buf/private/pkg/licenseheader/cmd/license-header@v1.51.0 89 | 90 | $(BIN)/golangci-lint: $(BIN) Makefile 91 | go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.0.2 92 | -------------------------------------------------------------------------------- /internal/protoyamltest/golden/golden.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package golden 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | 21 | "buf.build/go/protovalidate" 22 | "buf.build/go/protoyaml" 23 | testv1 "buf.build/go/protoyaml/internal/gen/proto/buf/protoyaml/test/v1" 24 | "google.golang.org/protobuf/proto" 25 | ) 26 | 27 | // protovalidateValidator is a temporary adapter that works with protovalidate-go v0.9.2 and later versions. 28 | // Newer versions (v0.9.3+) take functional options to the validate method so are incompatible w/ protoyaml's Validator. 29 | type protovalidateValidator struct { 30 | validator protovalidate.Validator 31 | } 32 | 33 | func (p *protovalidateValidator) Validate(message proto.Message) error { 34 | return p.validator.Validate(message) 35 | } 36 | 37 | // GenGoldenContent generates golden content for the given file path and data. 38 | // 39 | // If the data is invalid, the error message is returned as the golden content. 40 | // Otherwise, the golden content is the marshaled YAML data. 41 | func GenGoldenContent(filePath string, data []byte) (string, error) { 42 | validator, err := protovalidate.New() 43 | if err != nil { 44 | return "", err 45 | } 46 | 47 | options := protoyaml.UnmarshalOptions{ 48 | Validator: &protovalidateValidator{validator: validator}, 49 | Path: filePath, 50 | } 51 | var val proto.Message 52 | switch { 53 | case strings.HasSuffix(filePath, ".proto2test.yaml"): 54 | testCase := &testv1.Proto2Test{} 55 | err = options.Unmarshal(data, testCase) 56 | val = testCase 57 | case strings.HasSuffix(filePath, ".proto3test.yaml"): 58 | testCase := &testv1.Proto3Test{} 59 | err = options.Unmarshal(data, testCase) 60 | val = testCase 61 | case strings.HasSuffix(filePath, ".const.yaml"): 62 | testCase := &testv1.ConstValues{} 63 | err = options.Unmarshal(data, testCase) 64 | val = testCase 65 | case strings.HasSuffix(filePath, ".validate.yaml"): 66 | testCase := &testv1.ValidateTest{} 67 | err = options.Unmarshal(data, testCase) 68 | val = testCase 69 | default: 70 | return "", fmt.Errorf("unknown file type: %s", filePath) 71 | } 72 | if err != nil { 73 | return err.Error(), nil //nolint 74 | } 75 | opts := protoyaml.MarshalOptions{ 76 | UseProtoNames: true, 77 | } 78 | yamlData, err := opts.Marshal(val) 79 | if err != nil { 80 | return "", err 81 | } 82 | return string(yamlData), nil 83 | } 84 | -------------------------------------------------------------------------------- /encode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protoyaml 16 | 17 | import ( 18 | "bytes" 19 | "encoding/json" 20 | 21 | "google.golang.org/protobuf/encoding/protojson" 22 | "google.golang.org/protobuf/proto" 23 | "google.golang.org/protobuf/reflect/protoregistry" 24 | "gopkg.in/yaml.v3" 25 | ) 26 | 27 | // Marshal marshals the given message to YAML. 28 | func Marshal(message proto.Message) ([]byte, error) { 29 | return MarshalOptions{}.Marshal(message) 30 | } 31 | 32 | // MarshalOptions is a configurable YAML format marshaller. 33 | // 34 | // It uses similar options to protojson.MarshalOptions. 35 | type MarshalOptions struct { 36 | // The number of spaces to indent. Passed to yaml.Encoder.SetIndent. 37 | // If 0, uses the default indent of yaml.v3. 38 | Indent int 39 | // AllowPartial allows messages that have missing required fields to marshal 40 | // without returning an error. 41 | AllowPartial bool 42 | // UseProtoNames uses proto field name instead of lowerCamelCase name in YAML 43 | // field names. 44 | UseProtoNames bool 45 | // UseEnumNumbers emits enum values as numbers. 46 | UseEnumNumbers bool 47 | // EmitUnpopulated specifies whether to emit unpopulated fields. 48 | EmitUnpopulated bool 49 | // Resolver is used for looking up types when expanding google.protobuf.Any 50 | // messages. If nil, this defaults to using protoregistry.GlobalTypes. 51 | Resolver interface { 52 | protoregistry.ExtensionTypeResolver 53 | protoregistry.MessageTypeResolver 54 | } 55 | } 56 | 57 | // Marshal marshals the given message to YAML using the options in MarshalOptions. 58 | // Do not depend on the output to be stable across different versions. 59 | func (o MarshalOptions) Marshal(message proto.Message) ([]byte, error) { 60 | data, err := protojson.MarshalOptions{ 61 | AllowPartial: o.AllowPartial, 62 | UseProtoNames: o.UseProtoNames, 63 | UseEnumNumbers: o.UseEnumNumbers, 64 | EmitUnpopulated: o.EmitUnpopulated, 65 | Resolver: o.Resolver, 66 | }.Marshal(message) 67 | if err != nil { 68 | return nil, err 69 | } 70 | yamlVal, err := jsonDataToYAML(data) 71 | if err != nil { 72 | return nil, err 73 | } 74 | 75 | // Write the JSON back out as YAML 76 | buffer := &bytes.Buffer{} 77 | encoder := yaml.NewEncoder(buffer) 78 | encoder.SetIndent(o.Indent) 79 | if err := encoder.Encode(yamlVal); err != nil { 80 | return nil, err 81 | } 82 | return buffer.Bytes(), nil 83 | } 84 | 85 | func jsonDataToYAML(data []byte) (interface{}, error) { 86 | // YAML unmarshal preserves the order of fields, but is more restrictive than JSON. 87 | // Prefer it if the data is valid YAML. 88 | jsonNode := &yaml.Node{} 89 | if err := yaml.Unmarshal(data, jsonNode); err == nil { 90 | if jsonNode.Kind == yaml.DocumentNode { 91 | jsonNode = jsonNode.Content[0] 92 | } 93 | clearStyle(jsonNode) 94 | return jsonNode, nil 95 | } 96 | 97 | // If the data is not valid YAML (e.g. a string contains control characters), 98 | // fall back to JSON unmarshal, which loses field order, but is more permissive. 99 | var jsonValue interface{} 100 | if err := json.Unmarshal(data, &jsonValue); err != nil { 101 | return nil, err 102 | } 103 | return jsonValue, nil 104 | } 105 | 106 | // clearStyle removes all style information from the node and its children. 107 | // 108 | // Without this, the returned YAML will look exactly like the JSON input. 109 | // TODO: Allow yaml style information to be specified in proto. 110 | func clearStyle(node *yaml.Node) { 111 | node.Style = 0 112 | for _, child := range node.Content { 113 | clearStyle(child) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250425153114-8976f5be98c1.1 h1:YhMSc48s25kr7kv31Z8vf7sPUIq5YJva9z1mn/hAt0M= 2 | buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250425153114-8976f5be98c1.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U= 3 | buf.build/go/protovalidate v0.11.0 h1:qmX+1Z/t5lqlxQW6bNHnCGE9kX6yXBNul0jYFjD2r3Q= 4 | buf.build/go/protovalidate v0.11.0/go.mod h1:Ryhm9EyqOxO/jdqEBpH4mI/FUk2ULyYeuhR+QRhOgqc= 5 | cel.dev/expr v0.23.1 h1:K4KOtPCJQjVggkARsjG9RWXP6O4R73aHeJMa/dmCQQg= 6 | cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= 7 | github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= 8 | github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= 13 | github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= 14 | github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY= 15 | github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI= 16 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 17 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 18 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 19 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 20 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 21 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 22 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 23 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 24 | github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= 25 | github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= 26 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 27 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 28 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 29 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 30 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 31 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 32 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 33 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 34 | golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= 35 | golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= 36 | golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= 37 | golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= 38 | google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw= 39 | google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= 40 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= 41 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= 42 | google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= 43 | google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 44 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 45 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 46 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 47 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 48 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 49 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 50 | -------------------------------------------------------------------------------- /internal/testdata/basic.proto3test.yaml: -------------------------------------------------------------------------------- 1 | # Constant values to test. 2 | values: 3 | - single_bool: true 4 | - single_bool: false 5 | - 13: true # single_bool has a field number of 13 6 | - singleBool: false # The 'json name' of single_bool is singleBool 7 | - single_bool: 1 8 | - single_bool: 0 9 | - single_bool: "true" 10 | - single_bool: "false" 11 | - single_bool: True 12 | - single_bool: False 13 | - single_bool: TRUE 14 | - single_bool: FALSE 15 | - single_bool: yes 16 | - single_bool: no 17 | - single_bool: [] 18 | - single_bool: {} 19 | - single_int32: 0 20 | - single_sfixed32: 1 21 | - single_sint32: 1.0 22 | - single_int32: -1 23 | - single_int32: 2147483647 24 | - single_int32: -2147483648 25 | - single_int32: 2147483648 26 | - single_int32: -2147483649 27 | - single_int32: 0x7fffffff 28 | - single_int32: -0X80000000 29 | - single_int32: 0X80000000 30 | - single_int32: -0x80000001 31 | - single_int32: 0o17777777777 32 | - single_int32: -0O20000000000 33 | - single_int32: 0O20000000000 34 | - single_int32: -0o20000000001 35 | - single_int32: 0b1111111111111111111111111111111 36 | - single_int32: -0B10000000000000000000000000000000 37 | - single_int32: 0B10000000000000000000000000000000 38 | - single_int32: -0b10000000000000000000000000000001 39 | - single_int32: 1.5 40 | - single_int32: 1.0e1 41 | - single_int32: 1.0 42 | - single_int32: 5.0e-1 43 | - single_int64: 0 44 | - single_sint64: 1 45 | - single_sfixed64: 1.0 46 | - single_int64: 9223372036854775807 47 | - single_int64: -9223372036854775808 48 | - single_int64: 9223372036854775808 49 | - single_int64: -9223372036854775809 50 | - single_int64: 9007199254740991.0 51 | - single_int64: 9007199254740992.0 52 | - single_int32: --1 53 | - single_int32: ---1 54 | - single_int32: inf 55 | - single_int32: .inf 56 | - single_int32: -.inf 57 | - single_int32: .nan 58 | - single_uint32: -1 59 | - single_uint64: 0 60 | - single_fixed32: 1.0 61 | - single_fixed64: 1.0 62 | - single_uint32: 4294967295 63 | - single_uint32: 4294967296 64 | - single_uint64: 18446744073709551615 65 | - single_uint64: 18446744073709551616 66 | - single_float: 1.0 67 | - single_float: 1 68 | - single_float: 1.0e1 69 | # Maximum representable value in single precision is 2^128 - 2^104 70 | - single_float: 1.7014118346046923e+38 71 | - single_float: 1.7014118346046923e+39 72 | - single_float: INF 73 | - single_float: inf 74 | - single_double: -inf 75 | - single_double: nan 76 | - single_double: Infinity 77 | - single_string: 1 78 | - single_string: 1.0 79 | - single_string: true 80 | - single_string: false 81 | - single_string: null 82 | - single_string: "null" 83 | - single_string: [] 84 | - single_string: {} 85 | - single_string: "1" 86 | - single_string: "\U0001F600" 87 | - single_bytes: bad base64 88 | - single_bytes: good 89 | - single_bytes: GOOD 90 | - single_bytes: "Zg==" 91 | - standalone_enum: -1 92 | - standalone_enum: 0 93 | - standalone_enum: 1 94 | - standalone_enum: 100 95 | - standalone_enum: UNKNOWN 96 | - standalone_enum: FOO 97 | - standalone_enum: foo 98 | - repeated_int32: 1 99 | - repeated_int32: [1] 100 | - repeated_int32: [1, "1", hi] 101 | - repeated_int32: {} 102 | - repeated_int32: [[]] 103 | - repeated_int32: [[1]] 104 | - standalone_message: 1 105 | - standalone_message: [] 106 | - standalone_message: {} 107 | - single_duration: 1 108 | - single_duration: 1s 109 | - single_duration: 1.123456789s 110 | - single_duration: 1.0123456789s 111 | - single_duration: As 112 | - single_duration: A.1s 113 | - single_duration: 1.1.1s 114 | - single_duration: 1.Bs 115 | - single_duration: 116 | seconds: 1 117 | nanos: 2 118 | - single_timestamp: 0001-01-01T00:00:00Z 119 | - single_timestamp: 0000-01-01T00:00:00Z 120 | - single_timestamp: 9999-12-31T23:59:59.999999999Z 121 | - single_timestamp: 9999-12-31T23:59:60Z 122 | - single_timestamp: 1970-01-01T00:00:00Z 123 | - single_timestamp: 1970-01-01T00:00:00.000000000Z 124 | - single_timestamp: 1970-01-01T00:00:00.000000001Z 125 | - single_timestamp: 10 126 | - single_timestamp: hello 127 | - single_timestamp: 128 | seconds: 1 129 | nanos: 2 130 | - single_timestamp: [] 131 | - single_int32_wrapper: 1 132 | - single_int32_wrapper: 133 | value: 1 134 | - single_int32_wrapper: 135 | "@type": type.googleapis.com/google.protobuf.Int32Value 136 | value: 1 137 | - single_bytes: "nopad+" 138 | - single_bytes: "web-safe__" 139 | - single_fixed64: 1E 140 | - single_fixed64: 1.0Mi 141 | - single_fixed64: 1.1Gi 142 | - single_fixed64: 1000Ei 143 | - single_int32: 1k 144 | - single_int32: -1Ki 145 | - single_int32: -1Ti 146 | - single_int32: 1Ai 147 | - single_int32: 1.1 148 | - single_int32: 1Mi1Ki 149 | - single_int32: 0x2.p10 150 | - single_fixed64: "" 151 | - standalone_enum: 1k 152 | -------------------------------------------------------------------------------- /internal/testdata/dynamic.const.yaml: -------------------------------------------------------------------------------- 1 | values: 2 | dynamic_bool_true: 3 | "@type": type.googleapis.com/google.protobuf.BoolValue 4 | value: true 5 | dynamic_bool_false: 6 | "@type": type.googleapis.com/google.protobuf.BoolValue 7 | value: false 8 | dynamic_bool_bad_list: 9 | "@type": type.googleapis.com/google.protobuf.BoolValue 10 | value: [] 11 | dynamic_bool_bad_struct: 12 | "@type": type.googleapis.com/google.protobuf.BoolValue 13 | value: {} 14 | dynamic_bool_bad_null: 15 | "@type": type.googleapis.com/google.protobuf.BoolValue 16 | value: null 17 | dynamic_number_bad_bool: 18 | "@type": type.googleapis.com/google.protobuf.Int32Value 19 | value: true 20 | dynamic_string_bool: 21 | "@type": type.googleapis.com/google.protobuf.StringValue 22 | value: true 23 | dynamic_string_number: 24 | "@type": type.googleapis.com/google.protobuf.StringValue 25 | value: 1 26 | dynamic_string_null: 27 | "@type": type.googleapis.com/google.protobuf.StringValue 28 | value: null 29 | dynamic_string_bad_list: 30 | "@type": type.googleapis.com/google.protobuf.StringValue 31 | value: [] 32 | dynamic_proto3_wkt: 33 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 34 | single_bool_wrapper: true 35 | dynamic_proto3_wkt_bad: 36 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 37 | single_bool_wrapper: "true" 38 | dynamic_proto3_list_bad_scalar: 39 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 40 | repeated_int32: 1 41 | dynamic_proto3_list_bad_map: 42 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 43 | repeated_int32: {} 44 | dynamic_proto3_list_bad_element: 45 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 46 | repeated_int32: [1, "1", 1.5, hi, Infinity, NaN] 47 | dynamic_proto3_list_float: 48 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 49 | repeated_float: [1, "1", 1.5, hi, Infinity, NaN, 16777215, 16777216, 16777217] 50 | dynamic_proto3_list_double: 51 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 52 | repeated_double: [1, "1", 1.5, hi, Infinity, NaN, 9007199254740991, 9007199254740992, 9007199254740993] 53 | dynamic_proto3_list_bytes: 54 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 55 | repeated_bytes: [1, "1", 1.5, hi, Infinity, NaN, "Zg==", true, false, null] 56 | dynamic_proto3_list_string: 57 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 58 | repeated_string: [1, "1", 1.5, hi, Infinity, NaN, "Zg==", true] 59 | dynamic_proto3_list_msg: 60 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 61 | repeated_nested_message: 62 | - bb: [] 63 | - bb: "1" 64 | dynamic_bool_true_alt: 65 | "@type": type.googleapis.com/google.protobuf.BoolValue 66 | value: True 67 | dynamic_bad_map_key: 68 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 69 | map_bool_bool: 70 | []: true 71 | 1: true 72 | true: 1 73 | dynamic_any: 74 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 75 | single_any: 76 | "@type": type.googleapis.com/google.protobuf.BoolValue 77 | value: hi 78 | dynamic_number_errors: 79 | "@type": type.googleapis.com/bufext.cel.expr.conformance.proto3.TestAllTypes 80 | repeated_int32: [1.5, -2147483648, -2147483649, 2147483647, 2147483648] 81 | repeated_int64: [1.5, -9223372036854775808, -9223372036854775809, 9223372036854775807, 9223372036854775808] 82 | repeated_uint32: [1.5, -1, 0, 4294967295, 4294967296] 83 | repeated_uint64: [1.5, -1, 0, 18446744073709551615, 18446744073709551616] 84 | repeated_float: [1.5, 16777215, 16777216, 16777217, 1.7014118346046923e+38, 1.7014118346046923e+39] 85 | repeated_double: [1.5, 9007199254740991, 9007199254740992, 9007199254740993] 86 | dynamic_duration_bad: 87 | "@type": type.googleapis.com/google.protobuf.Duration 88 | seconds: 1 89 | nanos: 1 90 | dynamic_duration: 91 | "@type": type.googleapis.com/google.protobuf.Duration 92 | value: 1.000000001s 93 | dynamic_any_any: 94 | "@type": type.googleapis.com/google.protobuf.Any 95 | value: 96 | "@type": type.googleapis.com/google.protobuf.Any 97 | value: 98 | "@type": type.googleapis.com/google.protobuf.BoolValue 99 | value: true 100 | dynamic_struct: 101 | "@type": type.googleapis.com/google.protobuf.Struct 102 | value: 103 | my_field: true 104 | other_field: 1 105 | dynamic_list: 106 | "@type": type.googleapis.com/google.protobuf.ListValue 107 | value: 108 | - true 109 | - 1 110 | dynamic_no_value: 111 | "@type": type.googleapis.com/google.protobuf.BoolValue 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ProtoYAML 2 | 3 | [![Build](https://github.com/bufbuild/protoyaml-go/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/bufbuild/protoyaml-go/actions/workflows/ci.yaml) 4 | [![Report Card](https://goreportcard.com/badge/buf.build/go/protoyaml)](https://goreportcard.com/report/buf.build/go/protoyaml) 5 | [![GoDoc](https://pkg.go.dev/badge/buf.build/go/protoyaml.svg)](https://pkg.go.dev/buf.build/go/protoyaml) 6 | 7 | Marshal and unmarshal Protocol Buffers as YAML. Provides fine-grained error details with file, line, column and snippet information. 8 | 9 | Fully compatible with [protojson](https://github.com/protocolbuffers/protobuf-go/tree/master/encoding/protojson). 10 | 11 | ## Usage 12 | 13 | ```go 14 | package main 15 | 16 | import ( 17 | "log" 18 | 19 | "buf.build/go/protoyaml" 20 | ) 21 | 22 | func main() { 23 | // Marshal a proto message to YAML. 24 | yamlBytes, err := protoyaml.Marshal( 25 | &pb.MyMessage{ 26 | MyField: "hello world", 27 | }, 28 | ) 29 | if err != nil { 30 | log.Fatal(err) 31 | } 32 | 33 | // Unmarshal a proto message from YAML. 34 | options := protoyaml.UnmarshalOptions{ 35 | Path: "testdata/basic.proto3test.yaml", 36 | } 37 | var myMessage pb.MyMessage 38 | if err := options.Unmarshal(yamlBytes, &myMessage); err != nil { 39 | log.Fatal(err) 40 | } 41 | } 42 | ``` 43 | 44 | ProtoYAML returns either `nil` or an error with a detailed message. For every error found in the file, the error 45 | message includes the file name (if `Path` is set on `UnmarshalOptions`), line number, column number, and snippet 46 | of the YAML that caused the error. For example, when unmarshalling the following YAML file: 47 | 48 | ```yaml 49 | values: 50 | - single_bool: true 51 | - single_bool: false 52 | - single_bool: 1 53 | - single_bool: 0 54 | - single_bool: "true" 55 | - single_bool: "false" 56 | - single_bool: True 57 | - single_bool: False 58 | - single_bool: TRUE 59 | - single_bool: FALSE 60 | - single_bool: yes 61 | - single_bool: no 62 | ``` 63 | 64 | The following errors are returned: 65 | 66 | ``` 67 | testdata/basic.proto3test.yaml:5:18: expected bool, got "1" 68 | 5 | - single_bool: 1 69 | | .................^ 70 | testdata/basic.proto3test.yaml:6:18: expected bool, got "0" 71 | 6 | - single_bool: 0 72 | | .................^ 73 | testdata/basic.proto3test.yaml:7:18: expected tag !!bool, got !!str 74 | 7 | - single_bool: "true" 75 | | .................^ 76 | testdata/basic.proto3test.yaml:8:18: expected tag !!bool, got !!str 77 | 8 | - single_bool: "false" 78 | | .................^ 79 | testdata/basic.proto3test.yaml:9:18: expected bool, got "True" 80 | 9 | - single_bool: True 81 | | .................^ 82 | testdata/basic.proto3test.yaml:10:18: expected bool, got "False" 83 | 10 | - single_bool: False 84 | | .................^ 85 | testdata/basic.proto3test.yaml:11:18: expected bool, got "TRUE" 86 | 11 | - single_bool: TRUE 87 | | .................^ 88 | testdata/basic.proto3test.yaml:12:18: expected bool, got "FALSE" 89 | 12 | - single_bool: FALSE 90 | | .................^ 91 | testdata/basic.proto3test.yaml:13:18: expected bool, got "yes" 92 | 13 | - single_bool: yes 93 | | .................^ 94 | testdata/basic.proto3test.yaml:14:18: expected bool, got "no" 95 | 14 | - single_bool: no 96 | | .................^ 97 | ``` 98 | 99 | Only `true` and `false` are valid values for the `single_bool` field. 100 | 101 | For more examples, see the [internal/testdata](internal/testdata) directory. 102 | 103 | ## Validation 104 | 105 | ProtoYAML can integrate with external validation libraries such as 106 | [Protovalidate](https://github.com/bufbuild/protovalidate-go) to provide additional rich error 107 | information. Simply provide a `Validator` to the `UnmarshalOptions`: 108 | 109 | ```go 110 | package main 111 | 112 | import ( 113 | "log" 114 | 115 | "buf.build/go/protoyaml" 116 | "buf.build/go/protovalidate" 117 | ) 118 | 119 | func main() { 120 | validator, err := protovalidate.NewValidator() 121 | if err != nil { 122 | log.Fatal(err) 123 | } 124 | 125 | var myMessage pb.MyMessage 126 | options := protoyaml.UnmarshalOptions{ 127 | Path: "testdata/basic.proto3test.yaml", 128 | Validator: validator, 129 | } 130 | if err := options.Unmarshal(yamlBytes, &myMessage); err != nil { 131 | log.Fatal(err) 132 | } 133 | } 134 | ``` 135 | 136 | The errors produced by the `Validator` will show up along side the ProtoYAML errors. For example: 137 | 138 | ``` 139 | testdata/validate.validate.yaml:4:18 cases[2].float_gt_lt: value must be greater than 0 and less than 10 (float.gt_lt) 140 | 4 | - float_gt_lt: 10.5 141 | | .................^ 142 | ``` 143 | 144 | ## Status: Beta 145 | 146 | ProtoYAML is not yet stable. However, the final shape is unlikely to change drastically—future edits will be somewhat minor. 147 | 148 | ## Legal 149 | 150 | Offered under the [Apache 2 license](https://github.com/bufbuild/protoyaml-go/blob/main/LICENSE) 151 | -------------------------------------------------------------------------------- /encode_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protoyaml 16 | 17 | import ( 18 | "math" 19 | "testing" 20 | 21 | "buf.build/go/protoyaml/internal/gen/proto/bufext/cel/expr/conformance/proto3" 22 | ) 23 | 24 | func TestFloatJsonEncoding(t *testing.T) { 25 | t.Parallel() 26 | ival := &proto3.TestAllTypes{ 27 | // inf, -inf, and nan are not valid JSON values, so we expect them to be encoded as strings. 28 | RepeatedDouble: []float64{math.Inf(1), math.Inf(-1), math.NaN()}, 29 | } 30 | // Encode the message as YAML 31 | data, err := Marshal(ival) 32 | if err != nil { 33 | t.Fatal(err) 34 | } 35 | 36 | // Decode the message from Yaml 37 | oval := &proto3.TestAllTypes{} 38 | if err := Unmarshal(data, oval); err != nil { 39 | t.Fatal(err) 40 | } 41 | if len(oval.GetRepeatedDouble()) != 3 { 42 | t.Fatalf("Expected 3 values, got %d", len(oval.GetRepeatedDouble())) 43 | } 44 | if !math.IsInf(oval.GetRepeatedDouble()[0], 1) { 45 | t.Fatalf("Expected +Inf, got %f", oval.GetRepeatedDouble()[0]) 46 | } 47 | if !math.IsInf(oval.GetRepeatedDouble()[1], -1) { 48 | t.Fatalf("Expected -Inf, got %f", oval.GetRepeatedDouble()[1]) 49 | } 50 | if !math.IsNaN(oval.GetRepeatedDouble()[2]) { 51 | t.Fatalf("Expected NaN, got %f", oval.GetRepeatedDouble()[2]) 52 | } 53 | } 54 | 55 | func TestStringEscaping(t *testing.T) { 56 | t.Parallel() 57 | ival := &proto3.TestAllTypes{ 58 | RepeatedString: []string{"\a\b\f\n\r\t\v\\\"\\'\x7f"}, 59 | } 60 | // Encode the message as YAML 61 | data, err := Marshal(ival) 62 | if err != nil { 63 | t.Fatal(err) 64 | } 65 | 66 | // Decode the message from Yaml 67 | oval := &proto3.TestAllTypes{} 68 | if err := Unmarshal(data, oval); err != nil { 69 | t.Fatal(err) 70 | } 71 | if len(oval.GetRepeatedString()) != 1 { 72 | t.Fatalf("Expected 1 value, got %d", len(oval.GetRepeatedString())) 73 | } 74 | if oval.GetRepeatedString()[0] != ival.GetRepeatedString()[0] { 75 | t.Fatalf("Expected %q, got %q", ival.GetRepeatedString()[0], oval.GetRepeatedString()[0]) 76 | } 77 | } 78 | 79 | func TestBytesEncoding(t *testing.T) { 80 | t.Parallel() 81 | ival := &proto3.TestAllTypes{ 82 | RepeatedBytes: [][]byte{{0x00, 0x01, 0x02}}, 83 | } 84 | // Encode the message as YAML 85 | data, err := Marshal(ival) 86 | if err != nil { 87 | t.Fatal(err) 88 | } 89 | 90 | // Decode the message from Yaml 91 | oval := &proto3.TestAllTypes{} 92 | if err := Unmarshal(data, oval); err != nil { 93 | t.Fatal(err) 94 | } 95 | if len(oval.GetRepeatedBytes()) != 1 { 96 | t.Fatalf("Expected 1 value, got %d", len(oval.GetRepeatedBytes())) 97 | } 98 | if string(oval.GetRepeatedBytes()[0]) != string(ival.GetRepeatedBytes()[0]) { 99 | t.Fatalf("Expected %q, got %q", ival.GetRepeatedBytes()[0], oval.GetRepeatedBytes()[0]) 100 | } 101 | } 102 | 103 | func TestEnumEncoding(t *testing.T) { 104 | t.Parallel() 105 | ival := &proto3.TestAllTypes{ 106 | RepeatedNestedEnum: []proto3.TestAllTypes_NestedEnum{proto3.TestAllTypes_BAR, -1, 0, 1, 100}, 107 | } 108 | // Encode the message as YAML 109 | data, err := Marshal(ival) 110 | if err != nil { 111 | t.Fatal(err) 112 | } 113 | 114 | // Decode the message from Yaml 115 | oval := &proto3.TestAllTypes{} 116 | if err := Unmarshal(data, oval); err != nil { 117 | t.Fatal(err) 118 | } 119 | 120 | if len(oval.GetRepeatedNestedEnum()) != 5 { 121 | t.Fatalf("Expected 5 values, got %d", len(oval.GetRepeatedNestedEnum())) 122 | } 123 | if oval.GetRepeatedNestedEnum()[0] != ival.GetRepeatedNestedEnum()[0] { 124 | t.Fatalf("Expected %v, got %v", ival.GetRepeatedNestedEnum()[0], oval.GetRepeatedNestedEnum()[0]) 125 | } 126 | if oval.GetRepeatedNestedEnum()[1] != ival.GetRepeatedNestedEnum()[1] { 127 | t.Fatalf("Expected %v, got %v", ival.GetRepeatedNestedEnum()[1], oval.GetRepeatedNestedEnum()[1]) 128 | } 129 | if oval.GetRepeatedNestedEnum()[2] != ival.GetRepeatedNestedEnum()[2] { 130 | t.Fatalf("Expected %v, got %v", ival.GetRepeatedNestedEnum()[2], oval.GetRepeatedNestedEnum()[2]) 131 | } 132 | if oval.GetRepeatedNestedEnum()[3] != ival.GetRepeatedNestedEnum()[3] { 133 | t.Fatalf("Expected %v, got %v", ival.GetRepeatedNestedEnum()[3], oval.GetRepeatedNestedEnum()[3]) 134 | } 135 | if oval.GetRepeatedNestedEnum()[4] != ival.GetRepeatedNestedEnum()[4] { 136 | t.Fatalf("Expected %v, got %v", ival.GetRepeatedNestedEnum()[4], oval.GetRepeatedNestedEnum()[4]) 137 | } 138 | } 139 | 140 | func TestIndentSize(t *testing.T) { 141 | t.Parallel() 142 | ival := &proto3.TestAllTypes{ 143 | RepeatedNestedEnum: []proto3.TestAllTypes_NestedEnum{proto3.TestAllTypes_BAR, -1, 0, 1, 100}, 144 | } 145 | // Encode the message as YAML 146 | data, err := MarshalOptions{Indent: 2}.Marshal(ival) 147 | if err != nil { 148 | t.Fatal(err) 149 | } 150 | if string(data) != "repeatedNestedEnum:\n - BAR\n - -1\n - FOO\n - BAR\n - 100\n" { 151 | t.Fatalf("Expected 2 space indent, got %q", string(data)) 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /internal/gen/proto/buf/protoyaml/test/v1/pb3.pb.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by protoc-gen-go. DO NOT EDIT. 16 | // versions: 17 | // protoc-gen-go v1.36.6 18 | // protoc (unknown) 19 | // source: buf/protoyaml/test/v1/pb3.proto 20 | 21 | package testv1 22 | 23 | import ( 24 | proto3 "buf.build/go/protoyaml/internal/gen/proto/bufext/cel/expr/conformance/proto3" 25 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 26 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 27 | reflect "reflect" 28 | sync "sync" 29 | unsafe "unsafe" 30 | ) 31 | 32 | const ( 33 | // Verify that this generated code is sufficiently up-to-date. 34 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 35 | // Verify that runtime/protoimpl is sufficiently up-to-date. 36 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 37 | ) 38 | 39 | type Proto3Test struct { 40 | state protoimpl.MessageState `protogen:"open.v1"` 41 | Values []*proto3.TestAllTypes `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` 42 | unknownFields protoimpl.UnknownFields 43 | sizeCache protoimpl.SizeCache 44 | } 45 | 46 | func (x *Proto3Test) Reset() { 47 | *x = Proto3Test{} 48 | mi := &file_buf_protoyaml_test_v1_pb3_proto_msgTypes[0] 49 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 50 | ms.StoreMessageInfo(mi) 51 | } 52 | 53 | func (x *Proto3Test) String() string { 54 | return protoimpl.X.MessageStringOf(x) 55 | } 56 | 57 | func (*Proto3Test) ProtoMessage() {} 58 | 59 | func (x *Proto3Test) ProtoReflect() protoreflect.Message { 60 | mi := &file_buf_protoyaml_test_v1_pb3_proto_msgTypes[0] 61 | if x != nil { 62 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 63 | if ms.LoadMessageInfo() == nil { 64 | ms.StoreMessageInfo(mi) 65 | } 66 | return ms 67 | } 68 | return mi.MessageOf(x) 69 | } 70 | 71 | // Deprecated: Use Proto3Test.ProtoReflect.Descriptor instead. 72 | func (*Proto3Test) Descriptor() ([]byte, []int) { 73 | return file_buf_protoyaml_test_v1_pb3_proto_rawDescGZIP(), []int{0} 74 | } 75 | 76 | func (x *Proto3Test) GetValues() []*proto3.TestAllTypes { 77 | if x != nil { 78 | return x.Values 79 | } 80 | return nil 81 | } 82 | 83 | var File_buf_protoyaml_test_v1_pb3_proto protoreflect.FileDescriptor 84 | 85 | const file_buf_protoyaml_test_v1_pb3_proto_rawDesc = "" + 86 | "\n" + 87 | "\x1fbuf/protoyaml/test/v1/pb3.proto\x12\x15buf.protoyaml.test.v1\x1a7bufext/cel/expr/conformance/proto3/test_all_types.proto\"V\n" + 88 | "\n" + 89 | "Proto3Test\x12H\n" + 90 | "\x06values\x18\x01 \x03(\v20.bufext.cel.expr.conformance.proto3.TestAllTypesR\x06valuesB\xe4\x01\n" + 91 | "\x19com.buf.protoyaml.test.v1B\bPb3ProtoP\x01ZFbuf.build/go/protoyaml/internal/gen/proto/buf/protoyaml/test/v1;testv1\xa2\x02\x03BPT\xaa\x02\x15Buf.Protoyaml.Test.V1\xca\x02\x15Buf\\Protoyaml\\Test\\V1\xe2\x02!Buf\\Protoyaml\\Test\\V1\\GPBMetadata\xea\x02\x18Buf::Protoyaml::Test::V1b\x06proto3" 92 | 93 | var ( 94 | file_buf_protoyaml_test_v1_pb3_proto_rawDescOnce sync.Once 95 | file_buf_protoyaml_test_v1_pb3_proto_rawDescData []byte 96 | ) 97 | 98 | func file_buf_protoyaml_test_v1_pb3_proto_rawDescGZIP() []byte { 99 | file_buf_protoyaml_test_v1_pb3_proto_rawDescOnce.Do(func() { 100 | file_buf_protoyaml_test_v1_pb3_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_pb3_proto_rawDesc), len(file_buf_protoyaml_test_v1_pb3_proto_rawDesc))) 101 | }) 102 | return file_buf_protoyaml_test_v1_pb3_proto_rawDescData 103 | } 104 | 105 | var file_buf_protoyaml_test_v1_pb3_proto_msgTypes = make([]protoimpl.MessageInfo, 1) 106 | var file_buf_protoyaml_test_v1_pb3_proto_goTypes = []any{ 107 | (*Proto3Test)(nil), // 0: buf.protoyaml.test.v1.Proto3Test 108 | (*proto3.TestAllTypes)(nil), // 1: bufext.cel.expr.conformance.proto3.TestAllTypes 109 | } 110 | var file_buf_protoyaml_test_v1_pb3_proto_depIdxs = []int32{ 111 | 1, // 0: buf.protoyaml.test.v1.Proto3Test.values:type_name -> bufext.cel.expr.conformance.proto3.TestAllTypes 112 | 1, // [1:1] is the sub-list for method output_type 113 | 1, // [1:1] is the sub-list for method input_type 114 | 1, // [1:1] is the sub-list for extension type_name 115 | 1, // [1:1] is the sub-list for extension extendee 116 | 0, // [0:1] is the sub-list for field type_name 117 | } 118 | 119 | func init() { file_buf_protoyaml_test_v1_pb3_proto_init() } 120 | func file_buf_protoyaml_test_v1_pb3_proto_init() { 121 | if File_buf_protoyaml_test_v1_pb3_proto != nil { 122 | return 123 | } 124 | type x struct{} 125 | out := protoimpl.TypeBuilder{ 126 | File: protoimpl.DescBuilder{ 127 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 128 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_pb3_proto_rawDesc), len(file_buf_protoyaml_test_v1_pb3_proto_rawDesc)), 129 | NumEnums: 0, 130 | NumMessages: 1, 131 | NumExtensions: 0, 132 | NumServices: 0, 133 | }, 134 | GoTypes: file_buf_protoyaml_test_v1_pb3_proto_goTypes, 135 | DependencyIndexes: file_buf_protoyaml_test_v1_pb3_proto_depIdxs, 136 | MessageInfos: file_buf_protoyaml_test_v1_pb3_proto_msgTypes, 137 | }.Build() 138 | File_buf_protoyaml_test_v1_pb3_proto = out.File 139 | file_buf_protoyaml_test_v1_pb3_proto_goTypes = nil 140 | file_buf_protoyaml_test_v1_pb3_proto_depIdxs = nil 141 | } 142 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | conduct@buf.build. All complaints will be reviewed and investigated promptly 64 | and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available 126 | at [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | 134 | -------------------------------------------------------------------------------- /internal/testdata/dynamic.const.txt: -------------------------------------------------------------------------------- 1 | internal/testdata/dynamic.const.yaml:10:12 expected scalar, got sequence 2 | 10 | value: [] 3 | 10 | ...........^ 4 | 5 | internal/testdata/dynamic.const.yaml:13:12 expected scalar, got mapping 6 | 13 | value: {} 7 | 13 | ...........^ 8 | 9 | internal/testdata/dynamic.const.yaml:16:12 expected bool, got "null" 10 | 16 | value: null 11 | 16 | ...........^ 12 | 13 | internal/testdata/dynamic.const.yaml:19:12 invalid integer: invalid number, expected digit 14 | 19 | value: true 15 | 19 | ...........^ 16 | 17 | internal/testdata/dynamic.const.yaml:31:12 expected scalar, got sequence 18 | 31 | value: [] 19 | 31 | ...........^ 20 | 21 | internal/testdata/dynamic.const.yaml:37:26 expected tag !!bool, got !!str 22 | 37 | single_bool_wrapper: "true" 23 | 37 | .........................^ 24 | 25 | internal/testdata/dynamic.const.yaml:40:21 expected sequence, got scalar 26 | 40 | repeated_int32: 1 27 | 40 | ....................^ 28 | 29 | internal/testdata/dynamic.const.yaml:43:21 expected sequence, got mapping 30 | 43 | repeated_int32: {} 31 | 43 | ....................^ 32 | 33 | internal/testdata/dynamic.const.yaml:46:30 invalid integer: precision loss 34 | 46 | repeated_int32: [1, "1", 1.5, hi, Infinity, NaN] 35 | 46 | .............................^ 36 | 37 | internal/testdata/dynamic.const.yaml:46:35 invalid integer: invalid number, expected digit 38 | 46 | repeated_int32: [1, "1", 1.5, hi, Infinity, NaN] 39 | 46 | ..................................^ 40 | 41 | internal/testdata/dynamic.const.yaml:46:39 invalid integer: strconv.ParseUint: parsing "Infinity": invalid syntax 42 | 46 | repeated_int32: [1, "1", 1.5, hi, Infinity, NaN] 43 | 46 | ......................................^ 44 | 45 | internal/testdata/dynamic.const.yaml:46:49 invalid integer: strconv.ParseUint: parsing "NaN": invalid syntax 46 | 46 | repeated_int32: [1, "1", 1.5, hi, Infinity, NaN] 47 | 46 | ................................................^ 48 | 49 | internal/testdata/dynamic.const.yaml:49:35 invalid float: strconv.ParseFloat: parsing "hi": invalid syntax 50 | 49 | repeated_float: [1, "1", 1.5, hi, Infinity, NaN, 16777215, 16777216, 16777217] 51 | 49 | ..................................^ 52 | 53 | internal/testdata/dynamic.const.yaml:52:36 invalid float: strconv.ParseFloat: parsing "hi": invalid syntax 54 | 52 | repeated_double: [1, "1", 1.5, hi, Infinity, NaN, 9007199254740991, 9007199254740992, 9007199254740993] 55 | 52 | ...................................^ 56 | 57 | internal/testdata/dynamic.const.yaml:55:22 invalid base64: illegal base64 data at input byte 0 58 | 55 | repeated_bytes: [1, "1", 1.5, hi, Infinity, NaN, "Zg==", true, false, null] 59 | 55 | .....................^ 60 | 61 | internal/testdata/dynamic.const.yaml:55:25 invalid base64: illegal base64 data at input byte 0 62 | 55 | repeated_bytes: [1, "1", 1.5, hi, Infinity, NaN, "Zg==", true, false, null] 63 | 55 | ........................^ 64 | 65 | internal/testdata/dynamic.const.yaml:55:30 invalid base64: illegal base64 data at input byte 1 66 | 55 | repeated_bytes: [1, "1", 1.5, hi, Infinity, NaN, "Zg==", true, false, null] 67 | 55 | .............................^ 68 | 69 | internal/testdata/dynamic.const.yaml:55:68 invalid base64: illegal base64 data at input byte 4 70 | 55 | repeated_bytes: [1, "1", 1.5, hi, Infinity, NaN, "Zg==", true, false, null] 71 | 55 | ...................................................................^ 72 | 73 | internal/testdata/dynamic.const.yaml:62:13 expected scalar, got sequence 74 | 62 | - bb: [] 75 | 62 | ............^ 76 | 77 | internal/testdata/dynamic.const.yaml:66:12 expected bool, got "True" 78 | 66 | value: True 79 | 66 | ...........^ 80 | 81 | internal/testdata/dynamic.const.yaml:70:7 expected scalar, got sequence 82 | 70 | []: true 83 | 70 | ......^ 84 | 85 | internal/testdata/dynamic.const.yaml:71:7 expected bool, got "1" 86 | 71 | 1: true 87 | 71 | ......^ 88 | 89 | internal/testdata/dynamic.const.yaml:72:13 expected bool, got "1" 90 | 72 | true: 1 91 | 72 | ............^ 92 | 93 | internal/testdata/dynamic.const.yaml:77:14 expected bool, got "hi" 94 | 77 | value: hi 95 | 77 | .............^ 96 | 97 | internal/testdata/dynamic.const.yaml:80:22 invalid integer: precision loss 98 | 80 | repeated_int32: [1.5, -2147483648, -2147483649, 2147483647, 2147483648] 99 | 80 | .....................^ 100 | 101 | internal/testdata/dynamic.const.yaml:80:40 integer is too small: < -2147483648 102 | 80 | repeated_int32: [1.5, -2147483648, -2147483649, 2147483647, 2147483648] 103 | 80 | .......................................^ 104 | 105 | internal/testdata/dynamic.const.yaml:80:65 integer is too large: > 2147483647 106 | 80 | repeated_int32: [1.5, -2147483648, -2147483649, 2147483647, 2147483648] 107 | 80 | ................................................................^ 108 | 109 | internal/testdata/dynamic.const.yaml:81:22 invalid integer: precision loss 110 | 81 | repeated_int64: [1.5, -9223372036854775808, -9223372036854775809, 9223372036854775807, 9223372036854775808] 111 | 81 | .....................^ 112 | 113 | internal/testdata/dynamic.const.yaml:81:49 integer is too small: < -9223372036854775808 114 | 81 | repeated_int64: [1.5, -9223372036854775808, -9223372036854775809, 9223372036854775807, 9223372036854775808] 115 | 81 | ................................................^ 116 | 117 | internal/testdata/dynamic.const.yaml:81:92 integer is too large: > 9223372036854775807 118 | 81 | repeated_int64: [1.5, -9223372036854775808, -9223372036854775809, 9223372036854775807, 9223372036854775808] 119 | 81 | ...........................................................................................^ 120 | 121 | internal/testdata/dynamic.const.yaml:82:23 invalid integer: precision loss 122 | 82 | repeated_uint32: [1.5, -1, 0, 4294967295, 4294967296] 123 | 82 | ......................^ 124 | 125 | internal/testdata/dynamic.const.yaml:82:28 invalid integer: strconv.ParseUint: parsing "-1": invalid syntax 126 | 82 | repeated_uint32: [1.5, -1, 0, 4294967295, 4294967296] 127 | 82 | ...........................^ 128 | 129 | internal/testdata/dynamic.const.yaml:82:47 integer is too large: > 4294967295 130 | 82 | repeated_uint32: [1.5, -1, 0, 4294967295, 4294967296] 131 | 82 | ..............................................^ 132 | 133 | internal/testdata/dynamic.const.yaml:83:23 invalid integer: precision loss 134 | 83 | repeated_uint64: [1.5, -1, 0, 18446744073709551615, 18446744073709551616] 135 | 83 | ......................^ 136 | 137 | internal/testdata/dynamic.const.yaml:83:28 invalid integer: strconv.ParseUint: parsing "-1": invalid syntax 138 | 83 | repeated_uint64: [1.5, -1, 0, 18446744073709551615, 18446744073709551616] 139 | 83 | ...........................^ 140 | 141 | internal/testdata/dynamic.const.yaml:83:57 invalid integer: precision loss 142 | 83 | repeated_uint64: [1.5, -1, 0, 18446744073709551615, 18446744073709551616] 143 | 83 | ........................................................^ 144 | 145 | internal/testdata/dynamic.const.yaml:84:81 invalid float: strconv.ParseFloat: parsing "1.7014118346046923e+39": value out of range 146 | 84 | repeated_float: [1.5, 16777215, 16777216, 16777217, 1.7014118346046923e+38, 1.7014118346046923e+39] 147 | 84 | ................................................................................^ 148 | 149 | internal/testdata/dynamic.const.yaml:88:5 unknown field "seconds", expended one of [value @type] 150 | 88 | seconds: 1 151 | 88 | ....^ 152 | 153 | internal/testdata/dynamic.const.yaml:111:5 missing "value" field 154 | 111 | "@type": type.googleapis.com/google.protobuf.BoolValue 155 | 111 | ....^ 156 | -------------------------------------------------------------------------------- /internal/gen/proto/buf/protoyaml/test/v1/const.pb.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by protoc-gen-go. DO NOT EDIT. 16 | // versions: 17 | // protoc-gen-go v1.36.6 18 | // protoc (unknown) 19 | // source: buf/protoyaml/test/v1/const.proto 20 | 21 | package testv1 22 | 23 | import ( 24 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 25 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 26 | descriptorpb "google.golang.org/protobuf/types/descriptorpb" 27 | anypb "google.golang.org/protobuf/types/known/anypb" 28 | reflect "reflect" 29 | sync "sync" 30 | unsafe "unsafe" 31 | ) 32 | 33 | const ( 34 | // Verify that this generated code is sufficiently up-to-date. 35 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 36 | // Verify that runtime/protoimpl is sufficiently up-to-date. 37 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 38 | ) 39 | 40 | type ConstValues struct { 41 | state protoimpl.MessageState `protogen:"open.v1"` 42 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // file name, relative to root of source tree 43 | Package string `protobuf:"bytes,2,opt,name=package,proto3" json:"package,omitempty"` // e.g. "foo", "foo.bar", etc. 44 | Dependency []string `protobuf:"bytes,3,rep,name=dependency,proto3" json:"dependency,omitempty"` 45 | Options *descriptorpb.FileOptions `protobuf:"bytes,8,opt,name=options,proto3" json:"options,omitempty"` 46 | Values map[string]*anypb.Any `protobuf:"bytes,4,rep,name=values,proto3" json:"values,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` 47 | unknownFields protoimpl.UnknownFields 48 | sizeCache protoimpl.SizeCache 49 | } 50 | 51 | func (x *ConstValues) Reset() { 52 | *x = ConstValues{} 53 | mi := &file_buf_protoyaml_test_v1_const_proto_msgTypes[0] 54 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 55 | ms.StoreMessageInfo(mi) 56 | } 57 | 58 | func (x *ConstValues) String() string { 59 | return protoimpl.X.MessageStringOf(x) 60 | } 61 | 62 | func (*ConstValues) ProtoMessage() {} 63 | 64 | func (x *ConstValues) ProtoReflect() protoreflect.Message { 65 | mi := &file_buf_protoyaml_test_v1_const_proto_msgTypes[0] 66 | if x != nil { 67 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 68 | if ms.LoadMessageInfo() == nil { 69 | ms.StoreMessageInfo(mi) 70 | } 71 | return ms 72 | } 73 | return mi.MessageOf(x) 74 | } 75 | 76 | // Deprecated: Use ConstValues.ProtoReflect.Descriptor instead. 77 | func (*ConstValues) Descriptor() ([]byte, []int) { 78 | return file_buf_protoyaml_test_v1_const_proto_rawDescGZIP(), []int{0} 79 | } 80 | 81 | func (x *ConstValues) GetName() string { 82 | if x != nil { 83 | return x.Name 84 | } 85 | return "" 86 | } 87 | 88 | func (x *ConstValues) GetPackage() string { 89 | if x != nil { 90 | return x.Package 91 | } 92 | return "" 93 | } 94 | 95 | func (x *ConstValues) GetDependency() []string { 96 | if x != nil { 97 | return x.Dependency 98 | } 99 | return nil 100 | } 101 | 102 | func (x *ConstValues) GetOptions() *descriptorpb.FileOptions { 103 | if x != nil { 104 | return x.Options 105 | } 106 | return nil 107 | } 108 | 109 | func (x *ConstValues) GetValues() map[string]*anypb.Any { 110 | if x != nil { 111 | return x.Values 112 | } 113 | return nil 114 | } 115 | 116 | var File_buf_protoyaml_test_v1_const_proto protoreflect.FileDescriptor 117 | 118 | const file_buf_protoyaml_test_v1_const_proto_rawDesc = "" + 119 | "\n" + 120 | "!buf/protoyaml/test/v1/const.proto\x12\x15buf.protoyaml.test.v1\x1a\x19google/protobuf/any.proto\x1a google/protobuf/descriptor.proto\"\xac\x02\n" + 121 | "\vConstValues\x12\x12\n" + 122 | "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" + 123 | "\apackage\x18\x02 \x01(\tR\apackage\x12\x1e\n" + 124 | "\n" + 125 | "dependency\x18\x03 \x03(\tR\n" + 126 | "dependency\x126\n" + 127 | "\aoptions\x18\b \x01(\v2\x1c.google.protobuf.FileOptionsR\aoptions\x12F\n" + 128 | "\x06values\x18\x04 \x03(\v2..buf.protoyaml.test.v1.ConstValues.ValuesEntryR\x06values\x1aO\n" + 129 | "\vValuesEntry\x12\x10\n" + 130 | "\x03key\x18\x01 \x01(\tR\x03key\x12*\n" + 131 | "\x05value\x18\x02 \x01(\v2\x14.google.protobuf.AnyR\x05value:\x028\x01B\xe6\x01\n" + 132 | "\x19com.buf.protoyaml.test.v1B\n" + 133 | "ConstProtoP\x01ZFbuf.build/go/protoyaml/internal/gen/proto/buf/protoyaml/test/v1;testv1\xa2\x02\x03BPT\xaa\x02\x15Buf.Protoyaml.Test.V1\xca\x02\x15Buf\\Protoyaml\\Test\\V1\xe2\x02!Buf\\Protoyaml\\Test\\V1\\GPBMetadata\xea\x02\x18Buf::Protoyaml::Test::V1b\x06proto3" 134 | 135 | var ( 136 | file_buf_protoyaml_test_v1_const_proto_rawDescOnce sync.Once 137 | file_buf_protoyaml_test_v1_const_proto_rawDescData []byte 138 | ) 139 | 140 | func file_buf_protoyaml_test_v1_const_proto_rawDescGZIP() []byte { 141 | file_buf_protoyaml_test_v1_const_proto_rawDescOnce.Do(func() { 142 | file_buf_protoyaml_test_v1_const_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_const_proto_rawDesc), len(file_buf_protoyaml_test_v1_const_proto_rawDesc))) 143 | }) 144 | return file_buf_protoyaml_test_v1_const_proto_rawDescData 145 | } 146 | 147 | var file_buf_protoyaml_test_v1_const_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 148 | var file_buf_protoyaml_test_v1_const_proto_goTypes = []any{ 149 | (*ConstValues)(nil), // 0: buf.protoyaml.test.v1.ConstValues 150 | nil, // 1: buf.protoyaml.test.v1.ConstValues.ValuesEntry 151 | (*descriptorpb.FileOptions)(nil), // 2: google.protobuf.FileOptions 152 | (*anypb.Any)(nil), // 3: google.protobuf.Any 153 | } 154 | var file_buf_protoyaml_test_v1_const_proto_depIdxs = []int32{ 155 | 2, // 0: buf.protoyaml.test.v1.ConstValues.options:type_name -> google.protobuf.FileOptions 156 | 1, // 1: buf.protoyaml.test.v1.ConstValues.values:type_name -> buf.protoyaml.test.v1.ConstValues.ValuesEntry 157 | 3, // 2: buf.protoyaml.test.v1.ConstValues.ValuesEntry.value:type_name -> google.protobuf.Any 158 | 3, // [3:3] is the sub-list for method output_type 159 | 3, // [3:3] is the sub-list for method input_type 160 | 3, // [3:3] is the sub-list for extension type_name 161 | 3, // [3:3] is the sub-list for extension extendee 162 | 0, // [0:3] is the sub-list for field type_name 163 | } 164 | 165 | func init() { file_buf_protoyaml_test_v1_const_proto_init() } 166 | func file_buf_protoyaml_test_v1_const_proto_init() { 167 | if File_buf_protoyaml_test_v1_const_proto != nil { 168 | return 169 | } 170 | type x struct{} 171 | out := protoimpl.TypeBuilder{ 172 | File: protoimpl.DescBuilder{ 173 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 174 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_const_proto_rawDesc), len(file_buf_protoyaml_test_v1_const_proto_rawDesc)), 175 | NumEnums: 0, 176 | NumMessages: 2, 177 | NumExtensions: 0, 178 | NumServices: 0, 179 | }, 180 | GoTypes: file_buf_protoyaml_test_v1_const_proto_goTypes, 181 | DependencyIndexes: file_buf_protoyaml_test_v1_const_proto_depIdxs, 182 | MessageInfos: file_buf_protoyaml_test_v1_const_proto_msgTypes, 183 | }.Build() 184 | File_buf_protoyaml_test_v1_const_proto = out.File 185 | file_buf_protoyaml_test_v1_const_proto_goTypes = nil 186 | file_buf_protoyaml_test_v1_const_proto_depIdxs = nil 187 | } 188 | -------------------------------------------------------------------------------- /decode_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protoyaml 16 | 17 | import ( 18 | "strings" 19 | "testing" 20 | "time" 21 | 22 | testv1 "buf.build/go/protoyaml/internal/gen/proto/buf/protoyaml/test/v1" 23 | "github.com/google/go-cmp/cmp" 24 | "github.com/stretchr/testify/assert" 25 | "github.com/stretchr/testify/require" 26 | "google.golang.org/protobuf/proto" 27 | "google.golang.org/protobuf/testing/protocmp" 28 | "google.golang.org/protobuf/types/known/durationpb" 29 | "google.golang.org/protobuf/types/known/timestamppb" 30 | "gopkg.in/yaml.v3" 31 | ) 32 | 33 | type testCustomUnmarshaler struct{} 34 | 35 | var _ CustomUnmarshaler = (*testCustomUnmarshaler)(nil) 36 | 37 | func (t *testCustomUnmarshaler) Unmarshal(node *yaml.Node, msg proto.Message) (bool, error) { 38 | if node.Kind != yaml.ScalarNode { 39 | return false, nil 40 | } 41 | protoTs, ok := msg.(*timestamppb.Timestamp) 42 | if !ok { 43 | return false, nil 44 | } 45 | 46 | switch strings.ToLower(node.Value) { 47 | case "epoch": 48 | proto.Reset(protoTs) 49 | return true, nil 50 | case "today": 51 | proto.Merge(protoTs, timestamppb.Now()) 52 | return true, nil 53 | case "tomorrow": 54 | proto.Merge(protoTs, timestamppb.New(time.Now().Add(24*time.Hour))) 55 | return true, nil 56 | case "yesterday": 57 | proto.Merge(protoTs, timestamppb.New(time.Now().Add(-24*time.Hour))) 58 | return true, nil 59 | } 60 | return false, nil 61 | } 62 | 63 | func TestCustomUnmarshal(t *testing.T) { 64 | t.Parallel() 65 | options := UnmarshalOptions{ 66 | CustomUnmarshaler: &testCustomUnmarshaler{}, 67 | } 68 | for _, testCase := range []struct { 69 | Input string 70 | Time time.Time 71 | }{ 72 | {Input: "epoch", Time: time.UnixMicro(0)}, 73 | {Input: "today", Time: time.Now()}, 74 | {Input: "tomorrow", Time: time.Now().Add(24 * time.Hour)}, 75 | {Input: "yesterday", Time: time.Now().Add(-24 * time.Hour)}, 76 | {Input: "2023-10-01T00:00:00Z", Time: time.Date(2023, 10, 1, 0, 0, 0, 0, time.UTC)}, 77 | } { 78 | t.Run(testCase.Input, func(t *testing.T) { 79 | t.Parallel() 80 | actual := ×tamppb.Timestamp{} 81 | err := options.Unmarshal([]byte(testCase.Input), actual) 82 | require.NoError(t, err) 83 | delta := actual.AsTime().Sub(testCase.Time) 84 | assert.LessOrEqual(t, delta, 1*time.Hour) 85 | }) 86 | } 87 | } 88 | 89 | func TestParseDuration(t *testing.T) { 90 | t.Parallel() 91 | for _, testCase := range []struct { 92 | Input string 93 | Expected *durationpb.Duration 94 | ErrMsg string 95 | }{ 96 | {Input: "", Expected: nil, ErrMsg: "invalid duration"}, 97 | {Input: "-", Expected: nil, ErrMsg: "invalid duration"}, 98 | {Input: "s", Expected: nil, ErrMsg: "invalid number"}, 99 | {Input: ".", Expected: nil, ErrMsg: "invalid number"}, 100 | {Input: "-s", Expected: nil, ErrMsg: "invalid number"}, 101 | {Input: ".s", Expected: nil, ErrMsg: "invalid number"}, 102 | {Input: "-.", Expected: nil, ErrMsg: "invalid number"}, 103 | {Input: "-.s", Expected: nil, ErrMsg: "invalid number"}, 104 | {Input: "--0s", Expected: nil, ErrMsg: "invalid number"}, 105 | {Input: "0y", Expected: nil, ErrMsg: "unknown unit"}, 106 | {Input: "0so", Expected: nil, ErrMsg: "unknown unit"}, 107 | {Input: "0os", Expected: nil, ErrMsg: "unknown unit"}, 108 | {Input: "0s-0ms", Expected: nil, ErrMsg: "invalid number"}, 109 | {Input: "0.5ns", Expected: nil, ErrMsg: "fractional nanos"}, 110 | {Input: "0.0005us", Expected: nil, ErrMsg: "fractional nanos"}, 111 | {Input: "0.0000005μs", Expected: nil, ErrMsg: "fractional nanos"}, 112 | {Input: "0.0000000005ms", Expected: nil, ErrMsg: "fractional nanos"}, 113 | {Input: "9223372036854775807s", Expected: &durationpb.Duration{Seconds: 9223372036854775807}}, 114 | {Input: "9223372036854775808s", ErrMsg: "out of range"}, 115 | {Input: "-9223372036854775808s", Expected: &durationpb.Duration{Seconds: -9223372036854775808}}, 116 | {Input: "-9223372036854775809s", ErrMsg: "out of range"}, 117 | {Input: "18446744073709551615s", ErrMsg: "out of range"}, 118 | {Input: "18446744073709551616s", ErrMsg: "overflow"}, 119 | {Input: "0"}, 120 | {Input: "0s"}, 121 | {Input: "-0s"}, 122 | {Input: "1s", Expected: &durationpb.Duration{Seconds: 1}}, 123 | {Input: "-1s", Expected: &durationpb.Duration{Seconds: -1}}, 124 | {Input: "1.5s", Expected: &durationpb.Duration{Seconds: 1, Nanos: 500000000}}, 125 | {Input: "-1.5s", Expected: &durationpb.Duration{Seconds: -1, Nanos: -500000000}}, 126 | {Input: "1.000000001s", Expected: &durationpb.Duration{Seconds: 1, Nanos: 1}}, 127 | {Input: "1.0000000001s", ErrMsg: "fractional nanos"}, 128 | {Input: "1.000000000s", Expected: &durationpb.Duration{Seconds: 1}}, 129 | {Input: "1.0000000010s", Expected: &durationpb.Duration{Seconds: 1, Nanos: 1}}, 130 | {Input: "1h", Expected: &durationpb.Duration{Seconds: 3600}}, 131 | {Input: "1m", Expected: &durationpb.Duration{Seconds: 60}}, 132 | {Input: "1h1m", Expected: &durationpb.Duration{Seconds: 3660}}, 133 | {Input: "1h1m1s", Expected: &durationpb.Duration{Seconds: 3661}}, 134 | {Input: "1h1m1.5s", Expected: &durationpb.Duration{Seconds: 3661, Nanos: 500000000}}, 135 | {Input: "1.5h1m1.5s", Expected: &durationpb.Duration{Seconds: 5461, Nanos: 500000000}}, 136 | {Input: "1.5h1m1.5s1.5h1m1.5s", Expected: &durationpb.Duration{Seconds: 10923}}, 137 | {Input: "1h1m1s1ms1us1μs1µs1ns", Expected: &durationpb.Duration{Seconds: 3661, Nanos: 1003001}}, 138 | } { 139 | t.Run(testCase.Input, func(t *testing.T) { 140 | t.Parallel() 141 | actual, err := ParseDuration(testCase.Input) 142 | if testCase.ErrMsg != "" { 143 | require.ErrorContains(t, err, testCase.ErrMsg) 144 | return 145 | } 146 | require.NoError(t, err) 147 | assert.Equal(t, testCase.Expected.GetSeconds(), actual.GetSeconds()) 148 | assert.Equal(t, testCase.Expected.GetNanos(), actual.GetNanos()) 149 | }) 150 | } 151 | } 152 | 153 | func TestExtension(t *testing.T) { 154 | t.Parallel() 155 | 156 | actual := &testv1.Proto2Test{} 157 | err := Unmarshal([]byte(`[buf.protoyaml.test.v1.p2t_string_ext]: hi`), actual) 158 | require.NoError(t, err) 159 | require.Equal(t, "hi", proto.GetExtension(actual, testv1.E_P2TStringExt)) 160 | } 161 | 162 | func TestEditions(t *testing.T) { 163 | t.Parallel() 164 | 165 | expected := &testv1.EditionsTest{ 166 | Name: proto.String("foobar"), 167 | Nested: &testv1.EditionsTest_Nested{ 168 | Ids: []int64{0, 1, 1, 2, 3, 5, 8}, 169 | }, 170 | Enum: testv1.OpenEnum_OPEN_ENUM_UNSPECIFIED, 171 | } 172 | actual := &testv1.EditionsTest{} 173 | data := []byte(` 174 | name: "foobar" 175 | enum: OPEN_ENUM_UNSPECIFIED 176 | nested: 177 | ids: [0, 1, 1, 2, 3, 5, 8]`) 178 | err := Unmarshal(data, actual) 179 | require.NoError(t, err) 180 | require.Empty(t, cmp.Diff(expected, actual, protocmp.Transform())) 181 | } 182 | 183 | func TestRequiredFields(t *testing.T) { 184 | t.Parallel() 185 | 186 | actual := &testv1.EditionsTest{} 187 | err := Unmarshal([]byte(`enum: OPEN_ENUM_UNSPECIFIED`), actual) 188 | require.ErrorContains(t, err, "required field buf.protoyaml.test.v1.EditionsTest.name not set") 189 | 190 | err = UnmarshalOptions{AllowPartial: true}.Unmarshal([]byte(`enum: OPEN_ENUM_UNSPECIFIED`), actual) 191 | require.NoError(t, err) 192 | expected := &testv1.EditionsTest{ 193 | Enum: testv1.OpenEnum_OPEN_ENUM_UNSPECIFIED, 194 | } 195 | require.Empty(t, cmp.Diff(expected, actual, protocmp.Transform())) 196 | } 197 | 198 | func TestDiscardUnknown(t *testing.T) { 199 | t.Parallel() 200 | 201 | data := []byte(` 202 | unknown: hi 203 | values: 204 | - oneof_string_value: hi 205 | `) 206 | 207 | actual := &testv1.Proto2Test{} 208 | err := Unmarshal(data, actual) 209 | require.Error(t, err) 210 | 211 | err = UnmarshalOptions{ 212 | DiscardUnknown: true, 213 | }.Unmarshal(data, actual) 214 | require.NoError(t, err) 215 | require.Equal(t, "hi", actual.GetValues()[0].GetOneofStringValue()) 216 | } 217 | -------------------------------------------------------------------------------- /internal/gen/proto/buf/protoyaml/test/v1/validate.pb.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by protoc-gen-go. DO NOT EDIT. 16 | // versions: 17 | // protoc-gen-go v1.36.6 18 | // protoc (unknown) 19 | // source: buf/protoyaml/test/v1/validate.proto 20 | 21 | package testv1 22 | 23 | import ( 24 | _ "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate" 25 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 26 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 27 | anypb "google.golang.org/protobuf/types/known/anypb" 28 | reflect "reflect" 29 | sync "sync" 30 | unsafe "unsafe" 31 | ) 32 | 33 | const ( 34 | // Verify that this generated code is sufficiently up-to-date. 35 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 36 | // Verify that runtime/protoimpl is sufficiently up-to-date. 37 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 38 | ) 39 | 40 | type ValidateTest struct { 41 | state protoimpl.MessageState `protogen:"open.v1"` 42 | Cases []*ValidateTestCase `protobuf:"bytes,1,rep,name=cases,proto3" json:"cases,omitempty"` 43 | unknownFields protoimpl.UnknownFields 44 | sizeCache protoimpl.SizeCache 45 | } 46 | 47 | func (x *ValidateTest) Reset() { 48 | *x = ValidateTest{} 49 | mi := &file_buf_protoyaml_test_v1_validate_proto_msgTypes[0] 50 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 51 | ms.StoreMessageInfo(mi) 52 | } 53 | 54 | func (x *ValidateTest) String() string { 55 | return protoimpl.X.MessageStringOf(x) 56 | } 57 | 58 | func (*ValidateTest) ProtoMessage() {} 59 | 60 | func (x *ValidateTest) ProtoReflect() protoreflect.Message { 61 | mi := &file_buf_protoyaml_test_v1_validate_proto_msgTypes[0] 62 | if x != nil { 63 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 64 | if ms.LoadMessageInfo() == nil { 65 | ms.StoreMessageInfo(mi) 66 | } 67 | return ms 68 | } 69 | return mi.MessageOf(x) 70 | } 71 | 72 | // Deprecated: Use ValidateTest.ProtoReflect.Descriptor instead. 73 | func (*ValidateTest) Descriptor() ([]byte, []int) { 74 | return file_buf_protoyaml_test_v1_validate_proto_rawDescGZIP(), []int{0} 75 | } 76 | 77 | func (x *ValidateTest) GetCases() []*ValidateTestCase { 78 | if x != nil { 79 | return x.Cases 80 | } 81 | return nil 82 | } 83 | 84 | type ValidateTestCase struct { 85 | state protoimpl.MessageState `protogen:"open.v1"` 86 | Dynamic *anypb.Any `protobuf:"bytes,1,opt,name=dynamic,proto3" json:"dynamic,omitempty"` 87 | FloatGtLt float32 `protobuf:"fixed32,2,opt,name=float_gt_lt,json=floatGtLt,proto3" json:"float_gt_lt,omitempty"` 88 | StringMap map[string]string `protobuf:"bytes,3,rep,name=string_map,json=stringMap,proto3" json:"string_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` 89 | unknownFields protoimpl.UnknownFields 90 | sizeCache protoimpl.SizeCache 91 | } 92 | 93 | func (x *ValidateTestCase) Reset() { 94 | *x = ValidateTestCase{} 95 | mi := &file_buf_protoyaml_test_v1_validate_proto_msgTypes[1] 96 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 97 | ms.StoreMessageInfo(mi) 98 | } 99 | 100 | func (x *ValidateTestCase) String() string { 101 | return protoimpl.X.MessageStringOf(x) 102 | } 103 | 104 | func (*ValidateTestCase) ProtoMessage() {} 105 | 106 | func (x *ValidateTestCase) ProtoReflect() protoreflect.Message { 107 | mi := &file_buf_protoyaml_test_v1_validate_proto_msgTypes[1] 108 | if x != nil { 109 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 110 | if ms.LoadMessageInfo() == nil { 111 | ms.StoreMessageInfo(mi) 112 | } 113 | return ms 114 | } 115 | return mi.MessageOf(x) 116 | } 117 | 118 | // Deprecated: Use ValidateTestCase.ProtoReflect.Descriptor instead. 119 | func (*ValidateTestCase) Descriptor() ([]byte, []int) { 120 | return file_buf_protoyaml_test_v1_validate_proto_rawDescGZIP(), []int{1} 121 | } 122 | 123 | func (x *ValidateTestCase) GetDynamic() *anypb.Any { 124 | if x != nil { 125 | return x.Dynamic 126 | } 127 | return nil 128 | } 129 | 130 | func (x *ValidateTestCase) GetFloatGtLt() float32 { 131 | if x != nil { 132 | return x.FloatGtLt 133 | } 134 | return 0 135 | } 136 | 137 | func (x *ValidateTestCase) GetStringMap() map[string]string { 138 | if x != nil { 139 | return x.StringMap 140 | } 141 | return nil 142 | } 143 | 144 | var File_buf_protoyaml_test_v1_validate_proto protoreflect.FileDescriptor 145 | 146 | const file_buf_protoyaml_test_v1_validate_proto_rawDesc = "" + 147 | "\n" + 148 | "$buf/protoyaml/test/v1/validate.proto\x12\x15buf.protoyaml.test.v1\x1a\x1bbuf/validate/validate.proto\x1a\x19google/protobuf/any.proto\"M\n" + 149 | "\fValidateTest\x12=\n" + 150 | "\x05cases\x18\x01 \x03(\v2'.buf.protoyaml.test.v1.ValidateTestCaseR\x05cases\"\xac\x02\n" + 151 | "\x10ValidateTestCase\x12.\n" + 152 | "\adynamic\x18\x01 \x01(\v2\x14.google.protobuf.AnyR\adynamic\x12/\n" + 153 | "\vfloat_gt_lt\x18\x02 \x01(\x02B\x0f\xbaH\f\n" + 154 | "\n" + 155 | "\x15\x00\x00 A%\x00\x00\x00\x00R\tfloatGtLt\x12y\n" + 156 | "\n" + 157 | "string_map\x18\x03 \x03(\v26.buf.protoyaml.test.v1.ValidateTestCase.StringMapEntryB\"\xbaH\x1f\x9a\x01\x1c\"\fr\n" + 158 | "2\b^[a-z]+$*\fr\n" + 159 | "2\b^[A-Z]+$R\tstringMap\x1a<\n" + 160 | "\x0eStringMapEntry\x12\x10\n" + 161 | "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + 162 | "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\xe9\x01\n" + 163 | "\x19com.buf.protoyaml.test.v1B\rValidateProtoP\x01ZFbuf.build/go/protoyaml/internal/gen/proto/buf/protoyaml/test/v1;testv1\xa2\x02\x03BPT\xaa\x02\x15Buf.Protoyaml.Test.V1\xca\x02\x15Buf\\Protoyaml\\Test\\V1\xe2\x02!Buf\\Protoyaml\\Test\\V1\\GPBMetadata\xea\x02\x18Buf::Protoyaml::Test::V1b\x06proto3" 164 | 165 | var ( 166 | file_buf_protoyaml_test_v1_validate_proto_rawDescOnce sync.Once 167 | file_buf_protoyaml_test_v1_validate_proto_rawDescData []byte 168 | ) 169 | 170 | func file_buf_protoyaml_test_v1_validate_proto_rawDescGZIP() []byte { 171 | file_buf_protoyaml_test_v1_validate_proto_rawDescOnce.Do(func() { 172 | file_buf_protoyaml_test_v1_validate_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_validate_proto_rawDesc), len(file_buf_protoyaml_test_v1_validate_proto_rawDesc))) 173 | }) 174 | return file_buf_protoyaml_test_v1_validate_proto_rawDescData 175 | } 176 | 177 | var file_buf_protoyaml_test_v1_validate_proto_msgTypes = make([]protoimpl.MessageInfo, 3) 178 | var file_buf_protoyaml_test_v1_validate_proto_goTypes = []any{ 179 | (*ValidateTest)(nil), // 0: buf.protoyaml.test.v1.ValidateTest 180 | (*ValidateTestCase)(nil), // 1: buf.protoyaml.test.v1.ValidateTestCase 181 | nil, // 2: buf.protoyaml.test.v1.ValidateTestCase.StringMapEntry 182 | (*anypb.Any)(nil), // 3: google.protobuf.Any 183 | } 184 | var file_buf_protoyaml_test_v1_validate_proto_depIdxs = []int32{ 185 | 1, // 0: buf.protoyaml.test.v1.ValidateTest.cases:type_name -> buf.protoyaml.test.v1.ValidateTestCase 186 | 3, // 1: buf.protoyaml.test.v1.ValidateTestCase.dynamic:type_name -> google.protobuf.Any 187 | 2, // 2: buf.protoyaml.test.v1.ValidateTestCase.string_map:type_name -> buf.protoyaml.test.v1.ValidateTestCase.StringMapEntry 188 | 3, // [3:3] is the sub-list for method output_type 189 | 3, // [3:3] is the sub-list for method input_type 190 | 3, // [3:3] is the sub-list for extension type_name 191 | 3, // [3:3] is the sub-list for extension extendee 192 | 0, // [0:3] is the sub-list for field type_name 193 | } 194 | 195 | func init() { file_buf_protoyaml_test_v1_validate_proto_init() } 196 | func file_buf_protoyaml_test_v1_validate_proto_init() { 197 | if File_buf_protoyaml_test_v1_validate_proto != nil { 198 | return 199 | } 200 | type x struct{} 201 | out := protoimpl.TypeBuilder{ 202 | File: protoimpl.DescBuilder{ 203 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 204 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_validate_proto_rawDesc), len(file_buf_protoyaml_test_v1_validate_proto_rawDesc)), 205 | NumEnums: 0, 206 | NumMessages: 3, 207 | NumExtensions: 0, 208 | NumServices: 0, 209 | }, 210 | GoTypes: file_buf_protoyaml_test_v1_validate_proto_goTypes, 211 | DependencyIndexes: file_buf_protoyaml_test_v1_validate_proto_depIdxs, 212 | MessageInfos: file_buf_protoyaml_test_v1_validate_proto_msgTypes, 213 | }.Build() 214 | File_buf_protoyaml_test_v1_validate_proto = out.File 215 | file_buf_protoyaml_test_v1_validate_proto_goTypes = nil 216 | file_buf_protoyaml_test_v1_validate_proto_depIdxs = nil 217 | } 218 | -------------------------------------------------------------------------------- /internal/protoyamltest/fuzz.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protoyamltest 16 | 17 | import ( 18 | "fmt" 19 | "math/rand" 20 | 21 | "google.golang.org/protobuf/proto" 22 | "google.golang.org/protobuf/reflect/protoreflect" 23 | "google.golang.org/protobuf/types/known/anypb" 24 | "google.golang.org/protobuf/types/known/durationpb" 25 | "google.golang.org/protobuf/types/known/structpb" 26 | "google.golang.org/protobuf/types/known/timestamppb" 27 | ) 28 | 29 | const maxDepth = 6 30 | 31 | // PopulateMessage populates the given message with random data. 32 | func PopulateMessage(msg proto.Message, seed int64) { 33 | populateMessage(rand.New(rand.NewSource(seed)), msg, 0) 34 | } 35 | 36 | func populateMessage(rnd *rand.Rand, msg proto.Message, depth int) { 37 | // Special cases for known types 38 | switch msg := msg.(type) { 39 | case *anypb.Any: 40 | // TODO: Populate with a known type 41 | return 42 | case *durationpb.Duration: 43 | // Valid values are between -315,576,000,000 and +315,576,000,000 inclusive. 44 | if rnd.Intn(2) == 0 { 45 | msg.Seconds = rnd.Int63n(631152000000) - 315576000000 46 | } else { 47 | msg.Seconds = 0 48 | } 49 | if rnd.Intn(2) == 0 { 50 | // Valid values are between 0 and +999,999,999 inclusive. 51 | msg.Nanos = rnd.Int31n(1000000000) 52 | } else { 53 | msg.Nanos = 0 54 | } 55 | switch { 56 | case msg.GetSeconds() < 0: 57 | msg.Nanos = -msg.GetNanos() 58 | case msg.GetSeconds() == 0: 59 | if rnd.Intn(2) == 0 { 60 | msg.Nanos = -msg.GetNanos() 61 | } 62 | } 63 | return 64 | case *timestamppb.Timestamp: 65 | // seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 66 | // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive. 67 | msg.Seconds = rnd.Int63n(253402300800) - 62135596800 68 | 69 | // Valid values are between 0 and +999,999,999 inclusive. 70 | msg.Nanos = rnd.Int31n(1000000000) 71 | return 72 | case *structpb.Value: 73 | // Exactly one field must be non-empty. 74 | idx := rnd.Intn(msg.ProtoReflect().Descriptor().Fields().Len()) 75 | field := msg.ProtoReflect().Descriptor().Fields().Get(idx) 76 | if field.Name() == "number_value" { 77 | // Must be finite. 78 | msg.Kind = &structpb.Value_NumberValue{NumberValue: rnd.Float64()} 79 | } else { 80 | populateField(rnd, field, msg, depth) 81 | } 82 | return 83 | } 84 | if depth > maxDepth { 85 | return 86 | } 87 | 88 | // For each field, decide whether to set it 89 | fields := msg.ProtoReflect().Descriptor().Fields() 90 | for i := range fields.Len() { 91 | field := fields.Get(i) 92 | if field.ContainingOneof() == nil { 93 | populateField(rnd, field, msg, depth+1) 94 | } 95 | } 96 | 97 | // For each oneof, decide which field to set. 98 | oneofs := msg.ProtoReflect().Descriptor().Oneofs() 99 | for i := range oneofs.Len() { 100 | oneof := oneofs.Get(i) 101 | oneofFields := oneof.Fields() 102 | idx := rnd.Intn(oneofFields.Len()) 103 | field := oneofFields.Get(idx) 104 | populateField(rnd, field, msg, depth) 105 | } 106 | } 107 | 108 | func populateField(rnd *rand.Rand, field protoreflect.FieldDescriptor, msg proto.Message, depth int) { 109 | switch { 110 | case field.IsList(): 111 | populateList(rnd, field, msg.ProtoReflect().Mutable(field).List(), depth) 112 | case field.IsMap(): 113 | populateMap(rnd, field, msg.ProtoReflect().Mutable(field).Map(), depth) 114 | case field.Message() != nil: 115 | populateMessage(rnd, msg.ProtoReflect().Mutable(field).Message().Interface(), depth) 116 | default: 117 | msg.ProtoReflect().Set(field, populateScalar(rnd, field)) 118 | } 119 | } 120 | 121 | func populateList(rnd *rand.Rand, field protoreflect.FieldDescriptor, list protoreflect.List, depth int) { 122 | if depth > maxDepth { 123 | return 124 | } 125 | length := rnd.Intn(10) 126 | for range length { 127 | switch field.Kind() { 128 | case protoreflect.MessageKind, protoreflect.GroupKind: 129 | msg := list.NewElement() 130 | populateMessage(rnd, msg.Message().Interface(), depth+1) 131 | list.Append(msg) 132 | default: 133 | list.Append(populateScalar(rnd, field)) 134 | } 135 | } 136 | } 137 | 138 | func populateMap(rnd *rand.Rand, field protoreflect.FieldDescriptor, mapVal protoreflect.Map, depth int) { 139 | if depth > maxDepth { 140 | return 141 | } 142 | keyField := field.MapKey() 143 | valueField := field.MapValue() 144 | switch keyField.Kind() { 145 | case protoreflect.BoolKind: 146 | switch rand.Intn(3) { 147 | case 0: 148 | populateMapValue(rnd, valueField, protoreflect.ValueOfBool(false).MapKey(), mapVal, depth+1) 149 | case 1: 150 | populateMapValue(rnd, valueField, protoreflect.ValueOfBool(true).MapKey(), mapVal, depth+1) 151 | case 2: 152 | populateMapValue(rnd, valueField, protoreflect.ValueOfBool(true).MapKey(), mapVal, depth+1) 153 | populateMapValue(rnd, valueField, protoreflect.ValueOfBool(false).MapKey(), mapVal, depth+1) 154 | } 155 | default: 156 | length := rnd.Intn(3) 157 | for range length { 158 | key := populateScalar(rnd, keyField) 159 | populateMapValue(rnd, valueField, key.MapKey(), mapVal, depth+1) 160 | } 161 | } 162 | } 163 | 164 | func populateMapValue(rnd *rand.Rand, field protoreflect.FieldDescriptor, mapKey protoreflect.MapKey, 165 | mapVal protoreflect.Map, depth int) { 166 | switch field.Kind() { 167 | case protoreflect.MessageKind, protoreflect.GroupKind: 168 | populateMessage(rnd, mapVal.Mutable(mapKey).Message().Interface(), depth) 169 | default: 170 | mapVal.Set(mapKey, populateScalar(rnd, field)) 171 | } 172 | } 173 | 174 | func populateI32(rnd *rand.Rand) protoreflect.Value { 175 | if rnd.Intn(2) == 0 { 176 | return protoreflect.ValueOfInt32(int32(rnd.Int())) 177 | } 178 | vals := interestingIntegers(32) 179 | return protoreflect.ValueOfInt32(int32(vals[rnd.Intn(len(vals))])) 180 | } 181 | 182 | func populateI64(rnd *rand.Rand) protoreflect.Value { 183 | if rnd.Intn(2) == 0 { 184 | return protoreflect.ValueOfInt64(int64(rnd.Int())) 185 | } 186 | vals := interestingIntegers(64) 187 | return protoreflect.ValueOfInt64(vals[rnd.Intn(len(vals))]) 188 | } 189 | 190 | func populateU32(rnd *rand.Rand) protoreflect.Value { 191 | if rnd.Intn(2) == 0 { 192 | return protoreflect.ValueOfUint32(rnd.Uint32()) 193 | } 194 | vals := interestingUnsigned(32) 195 | return protoreflect.ValueOfUint32(uint32(vals[rnd.Intn(len(vals))])) 196 | } 197 | 198 | func populateU64(rnd *rand.Rand) protoreflect.Value { 199 | if rnd.Intn(2) == 0 { 200 | return protoreflect.ValueOfUint64(rnd.Uint64()) 201 | } 202 | vals := interestingUnsigned(64) 203 | return protoreflect.ValueOfUint64(vals[rnd.Intn(len(vals))]) 204 | } 205 | 206 | func populateScalar(rnd *rand.Rand, field protoreflect.FieldDescriptor) protoreflect.Value { 207 | switch field.Kind() { 208 | case protoreflect.BoolKind: 209 | return protoreflect.ValueOfBool(rnd.Intn(2) == 0) 210 | case protoreflect.EnumKind: 211 | return populateEnum(rnd, field) 212 | case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: 213 | return populateI32(rnd) 214 | case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 215 | return populateI64(rnd) 216 | case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: 217 | return populateU32(rnd) 218 | case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 219 | return populateU64(rnd) 220 | case protoreflect.FloatKind: 221 | if rnd.Intn(2) == 0 { 222 | return protoreflect.ValueOfFloat32(rnd.Float32()) 223 | } 224 | vals := interestingFloats(32) 225 | return protoreflect.ValueOfFloat32(float32(vals[rnd.Intn(len(vals))])) 226 | case protoreflect.DoubleKind: 227 | vals := interestingFloats(64) 228 | return protoreflect.ValueOfFloat64(vals[rnd.Intn(len(vals))]) 229 | case protoreflect.StringKind: 230 | vals := interestingStrings() 231 | return protoreflect.ValueOfString(vals[rnd.Intn(len(vals))]) 232 | case protoreflect.BytesKind: 233 | vals := interestingBytes() 234 | return protoreflect.ValueOfBytes(vals[rnd.Intn(len(vals))]) 235 | default: 236 | panic(fmt.Sprintf("unknown scalar kind: %v", field.Kind())) 237 | } 238 | } 239 | 240 | func populateEnum(rnd *rand.Rand, field protoreflect.FieldDescriptor) protoreflect.Value { 241 | if field.Enum().FullName() == "google.protobuf.NullValue" { 242 | return protoreflect.ValueOfEnum(0) 243 | } 244 | values := field.Enum().Values() 245 | switch rand.Intn(3) { 246 | case 0: 247 | // Zero 248 | return protoreflect.ValueOfEnum(0) 249 | case 1: 250 | // Known value 251 | return protoreflect.ValueOfEnum(values.Get(rnd.Intn(values.Len())).Number()) 252 | case 2: 253 | // Random value 254 | return protoreflect.ValueOfEnum(protoreflect.EnumNumber(rnd.Int())) 255 | default: 256 | panic("unreachable") 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /internal/gen/proto/buf/protoyaml/test/v1/pb2.pb.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by protoc-gen-go. DO NOT EDIT. 16 | // versions: 17 | // protoc-gen-go v1.36.6 18 | // protoc (unknown) 19 | // source: buf/protoyaml/test/v1/pb2.proto 20 | 21 | package testv1 22 | 23 | import ( 24 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 25 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 26 | reflect "reflect" 27 | sync "sync" 28 | unsafe "unsafe" 29 | ) 30 | 31 | const ( 32 | // Verify that this generated code is sufficiently up-to-date. 33 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 34 | // Verify that runtime/protoimpl is sufficiently up-to-date. 35 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 36 | ) 37 | 38 | type Proto2Test struct { 39 | state protoimpl.MessageState `protogen:"open.v1"` 40 | Values []*Proto2TestValue `protobuf:"bytes,1,rep,name=values" json:"values,omitempty"` 41 | extensionFields protoimpl.ExtensionFields 42 | unknownFields protoimpl.UnknownFields 43 | sizeCache protoimpl.SizeCache 44 | } 45 | 46 | func (x *Proto2Test) Reset() { 47 | *x = Proto2Test{} 48 | mi := &file_buf_protoyaml_test_v1_pb2_proto_msgTypes[0] 49 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 50 | ms.StoreMessageInfo(mi) 51 | } 52 | 53 | func (x *Proto2Test) String() string { 54 | return protoimpl.X.MessageStringOf(x) 55 | } 56 | 57 | func (*Proto2Test) ProtoMessage() {} 58 | 59 | func (x *Proto2Test) ProtoReflect() protoreflect.Message { 60 | mi := &file_buf_protoyaml_test_v1_pb2_proto_msgTypes[0] 61 | if x != nil { 62 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 63 | if ms.LoadMessageInfo() == nil { 64 | ms.StoreMessageInfo(mi) 65 | } 66 | return ms 67 | } 68 | return mi.MessageOf(x) 69 | } 70 | 71 | // Deprecated: Use Proto2Test.ProtoReflect.Descriptor instead. 72 | func (*Proto2Test) Descriptor() ([]byte, []int) { 73 | return file_buf_protoyaml_test_v1_pb2_proto_rawDescGZIP(), []int{0} 74 | } 75 | 76 | func (x *Proto2Test) GetValues() []*Proto2TestValue { 77 | if x != nil { 78 | return x.Values 79 | } 80 | return nil 81 | } 82 | 83 | type Proto2TestValue struct { 84 | state protoimpl.MessageState `protogen:"open.v1"` 85 | // Types that are valid to be assigned to OneofValue: 86 | // 87 | // *Proto2TestValue_OneofStringValue 88 | // *Proto2TestValue_OneofInt32Value 89 | OneofValue isProto2TestValue_OneofValue `protobuf_oneof:"oneof_value"` 90 | unknownFields protoimpl.UnknownFields 91 | sizeCache protoimpl.SizeCache 92 | } 93 | 94 | func (x *Proto2TestValue) Reset() { 95 | *x = Proto2TestValue{} 96 | mi := &file_buf_protoyaml_test_v1_pb2_proto_msgTypes[1] 97 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 98 | ms.StoreMessageInfo(mi) 99 | } 100 | 101 | func (x *Proto2TestValue) String() string { 102 | return protoimpl.X.MessageStringOf(x) 103 | } 104 | 105 | func (*Proto2TestValue) ProtoMessage() {} 106 | 107 | func (x *Proto2TestValue) ProtoReflect() protoreflect.Message { 108 | mi := &file_buf_protoyaml_test_v1_pb2_proto_msgTypes[1] 109 | if x != nil { 110 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 111 | if ms.LoadMessageInfo() == nil { 112 | ms.StoreMessageInfo(mi) 113 | } 114 | return ms 115 | } 116 | return mi.MessageOf(x) 117 | } 118 | 119 | // Deprecated: Use Proto2TestValue.ProtoReflect.Descriptor instead. 120 | func (*Proto2TestValue) Descriptor() ([]byte, []int) { 121 | return file_buf_protoyaml_test_v1_pb2_proto_rawDescGZIP(), []int{1} 122 | } 123 | 124 | func (x *Proto2TestValue) GetOneofValue() isProto2TestValue_OneofValue { 125 | if x != nil { 126 | return x.OneofValue 127 | } 128 | return nil 129 | } 130 | 131 | func (x *Proto2TestValue) GetOneofStringValue() string { 132 | if x != nil { 133 | if x, ok := x.OneofValue.(*Proto2TestValue_OneofStringValue); ok { 134 | return x.OneofStringValue 135 | } 136 | } 137 | return "" 138 | } 139 | 140 | func (x *Proto2TestValue) GetOneofInt32Value() int32 { 141 | if x != nil { 142 | if x, ok := x.OneofValue.(*Proto2TestValue_OneofInt32Value); ok { 143 | return x.OneofInt32Value 144 | } 145 | } 146 | return 0 147 | } 148 | 149 | type isProto2TestValue_OneofValue interface { 150 | isProto2TestValue_OneofValue() 151 | } 152 | 153 | type Proto2TestValue_OneofStringValue struct { 154 | OneofStringValue string `protobuf:"bytes,1,opt,name=oneof_string_value,json=oneofStringValue,oneof"` 155 | } 156 | 157 | type Proto2TestValue_OneofInt32Value struct { 158 | OneofInt32Value int32 `protobuf:"varint,2,opt,name=oneof_int32_value,json=oneofInt32Value,oneof"` 159 | } 160 | 161 | func (*Proto2TestValue_OneofStringValue) isProto2TestValue_OneofValue() {} 162 | 163 | func (*Proto2TestValue_OneofInt32Value) isProto2TestValue_OneofValue() {} 164 | 165 | var file_buf_protoyaml_test_v1_pb2_proto_extTypes = []protoimpl.ExtensionInfo{ 166 | { 167 | ExtendedType: (*Proto2Test)(nil), 168 | ExtensionType: (*string)(nil), 169 | Field: 100, 170 | Name: "buf.protoyaml.test.v1.p2t_string_ext", 171 | Tag: "bytes,100,opt,name=p2t_string_ext", 172 | Filename: "buf/protoyaml/test/v1/pb2.proto", 173 | }, 174 | { 175 | ExtendedType: (*Proto2Test)(nil), 176 | ExtensionType: ([]string)(nil), 177 | Field: 101, 178 | Name: "buf.protoyaml.test.v1.p2t_repeated_string_ext", 179 | Tag: "bytes,101,rep,name=p2t_repeated_string_ext", 180 | Filename: "buf/protoyaml/test/v1/pb2.proto", 181 | }, 182 | } 183 | 184 | // Extension fields to Proto2Test. 185 | var ( 186 | // optional string p2t_string_ext = 100; 187 | E_P2TStringExt = &file_buf_protoyaml_test_v1_pb2_proto_extTypes[0] 188 | // repeated string p2t_repeated_string_ext = 101; 189 | E_P2TRepeatedStringExt = &file_buf_protoyaml_test_v1_pb2_proto_extTypes[1] 190 | ) 191 | 192 | var File_buf_protoyaml_test_v1_pb2_proto protoreflect.FileDescriptor 193 | 194 | const file_buf_protoyaml_test_v1_pb2_proto_rawDesc = "" + 195 | "\n" + 196 | "\x1fbuf/protoyaml/test/v1/pb2.proto\x12\x15buf.protoyaml.test.v1\"V\n" + 197 | "\n" + 198 | "Proto2Test\x12>\n" + 199 | "\x06values\x18\x01 \x03(\v2&.buf.protoyaml.test.v1.Proto2TestValueR\x06values*\b\bd\x10\x80\x80\x80\x80\x02\"~\n" + 200 | "\x0fProto2TestValue\x12.\n" + 201 | "\x12oneof_string_value\x18\x01 \x01(\tH\x00R\x10oneofStringValue\x12,\n" + 202 | "\x11oneof_int32_value\x18\x02 \x01(\x05H\x00R\x0foneofInt32ValueB\r\n" + 203 | "\voneof_value:G\n" + 204 | "\x0ep2t_string_ext\x12!.buf.protoyaml.test.v1.Proto2Test\x18d \x01(\tR\fp2tStringExt:X\n" + 205 | "\x17p2t_repeated_string_ext\x12!.buf.protoyaml.test.v1.Proto2Test\x18e \x03(\tR\x14p2tRepeatedStringExtB\xe4\x01\n" + 206 | "\x19com.buf.protoyaml.test.v1B\bPb2ProtoP\x01ZFbuf.build/go/protoyaml/internal/gen/proto/buf/protoyaml/test/v1;testv1\xa2\x02\x03BPT\xaa\x02\x15Buf.Protoyaml.Test.V1\xca\x02\x15Buf\\Protoyaml\\Test\\V1\xe2\x02!Buf\\Protoyaml\\Test\\V1\\GPBMetadata\xea\x02\x18Buf::Protoyaml::Test::V1" 207 | 208 | var ( 209 | file_buf_protoyaml_test_v1_pb2_proto_rawDescOnce sync.Once 210 | file_buf_protoyaml_test_v1_pb2_proto_rawDescData []byte 211 | ) 212 | 213 | func file_buf_protoyaml_test_v1_pb2_proto_rawDescGZIP() []byte { 214 | file_buf_protoyaml_test_v1_pb2_proto_rawDescOnce.Do(func() { 215 | file_buf_protoyaml_test_v1_pb2_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_pb2_proto_rawDesc), len(file_buf_protoyaml_test_v1_pb2_proto_rawDesc))) 216 | }) 217 | return file_buf_protoyaml_test_v1_pb2_proto_rawDescData 218 | } 219 | 220 | var file_buf_protoyaml_test_v1_pb2_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 221 | var file_buf_protoyaml_test_v1_pb2_proto_goTypes = []any{ 222 | (*Proto2Test)(nil), // 0: buf.protoyaml.test.v1.Proto2Test 223 | (*Proto2TestValue)(nil), // 1: buf.protoyaml.test.v1.Proto2TestValue 224 | } 225 | var file_buf_protoyaml_test_v1_pb2_proto_depIdxs = []int32{ 226 | 1, // 0: buf.protoyaml.test.v1.Proto2Test.values:type_name -> buf.protoyaml.test.v1.Proto2TestValue 227 | 0, // 1: buf.protoyaml.test.v1.p2t_string_ext:extendee -> buf.protoyaml.test.v1.Proto2Test 228 | 0, // 2: buf.protoyaml.test.v1.p2t_repeated_string_ext:extendee -> buf.protoyaml.test.v1.Proto2Test 229 | 3, // [3:3] is the sub-list for method output_type 230 | 3, // [3:3] is the sub-list for method input_type 231 | 3, // [3:3] is the sub-list for extension type_name 232 | 1, // [1:3] is the sub-list for extension extendee 233 | 0, // [0:1] is the sub-list for field type_name 234 | } 235 | 236 | func init() { file_buf_protoyaml_test_v1_pb2_proto_init() } 237 | func file_buf_protoyaml_test_v1_pb2_proto_init() { 238 | if File_buf_protoyaml_test_v1_pb2_proto != nil { 239 | return 240 | } 241 | file_buf_protoyaml_test_v1_pb2_proto_msgTypes[1].OneofWrappers = []any{ 242 | (*Proto2TestValue_OneofStringValue)(nil), 243 | (*Proto2TestValue_OneofInt32Value)(nil), 244 | } 245 | type x struct{} 246 | out := protoimpl.TypeBuilder{ 247 | File: protoimpl.DescBuilder{ 248 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 249 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_pb2_proto_rawDesc), len(file_buf_protoyaml_test_v1_pb2_proto_rawDesc)), 250 | NumEnums: 0, 251 | NumMessages: 2, 252 | NumExtensions: 2, 253 | NumServices: 0, 254 | }, 255 | GoTypes: file_buf_protoyaml_test_v1_pb2_proto_goTypes, 256 | DependencyIndexes: file_buf_protoyaml_test_v1_pb2_proto_depIdxs, 257 | MessageInfos: file_buf_protoyaml_test_v1_pb2_proto_msgTypes, 258 | ExtensionInfos: file_buf_protoyaml_test_v1_pb2_proto_extTypes, 259 | }.Build() 260 | File_buf_protoyaml_test_v1_pb2_proto = out.File 261 | file_buf_protoyaml_test_v1_pb2_proto_goTypes = nil 262 | file_buf_protoyaml_test_v1_pb2_proto_depIdxs = nil 263 | } 264 | -------------------------------------------------------------------------------- /internal/gen/proto/buf/protoyaml/test/v1/editions.pb.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by protoc-gen-go. DO NOT EDIT. 16 | // versions: 17 | // protoc-gen-go v1.36.6 18 | // protoc (unknown) 19 | // source: buf/protoyaml/test/v1/editions.proto 20 | 21 | package testv1 22 | 23 | import ( 24 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 25 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 26 | reflect "reflect" 27 | sync "sync" 28 | unsafe "unsafe" 29 | ) 30 | 31 | const ( 32 | // Verify that this generated code is sufficiently up-to-date. 33 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 34 | // Verify that runtime/protoimpl is sufficiently up-to-date. 35 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 36 | ) 37 | 38 | type OpenEnum int32 39 | 40 | const ( 41 | OpenEnum_OPEN_ENUM_UNSPECIFIED OpenEnum = 0 42 | ) 43 | 44 | // Enum value maps for OpenEnum. 45 | var ( 46 | OpenEnum_name = map[int32]string{ 47 | 0: "OPEN_ENUM_UNSPECIFIED", 48 | } 49 | OpenEnum_value = map[string]int32{ 50 | "OPEN_ENUM_UNSPECIFIED": 0, 51 | } 52 | ) 53 | 54 | func (x OpenEnum) Enum() *OpenEnum { 55 | p := new(OpenEnum) 56 | *p = x 57 | return p 58 | } 59 | 60 | func (x OpenEnum) String() string { 61 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 62 | } 63 | 64 | func (OpenEnum) Descriptor() protoreflect.EnumDescriptor { 65 | return file_buf_protoyaml_test_v1_editions_proto_enumTypes[0].Descriptor() 66 | } 67 | 68 | func (OpenEnum) Type() protoreflect.EnumType { 69 | return &file_buf_protoyaml_test_v1_editions_proto_enumTypes[0] 70 | } 71 | 72 | func (x OpenEnum) Number() protoreflect.EnumNumber { 73 | return protoreflect.EnumNumber(x) 74 | } 75 | 76 | // Deprecated: Use OpenEnum.Descriptor instead. 77 | func (OpenEnum) EnumDescriptor() ([]byte, []int) { 78 | return file_buf_protoyaml_test_v1_editions_proto_rawDescGZIP(), []int{0} 79 | } 80 | 81 | type ClosedEnum int32 82 | 83 | const ( 84 | ClosedEnum_CLOSED_ENUM_UNSPECIFIED ClosedEnum = 0 85 | ) 86 | 87 | // Enum value maps for ClosedEnum. 88 | var ( 89 | ClosedEnum_name = map[int32]string{ 90 | 0: "CLOSED_ENUM_UNSPECIFIED", 91 | } 92 | ClosedEnum_value = map[string]int32{ 93 | "CLOSED_ENUM_UNSPECIFIED": 0, 94 | } 95 | ) 96 | 97 | func (x ClosedEnum) Enum() *ClosedEnum { 98 | p := new(ClosedEnum) 99 | *p = x 100 | return p 101 | } 102 | 103 | func (x ClosedEnum) String() string { 104 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 105 | } 106 | 107 | func (ClosedEnum) Descriptor() protoreflect.EnumDescriptor { 108 | return file_buf_protoyaml_test_v1_editions_proto_enumTypes[1].Descriptor() 109 | } 110 | 111 | func (ClosedEnum) Type() protoreflect.EnumType { 112 | return &file_buf_protoyaml_test_v1_editions_proto_enumTypes[1] 113 | } 114 | 115 | func (x ClosedEnum) Number() protoreflect.EnumNumber { 116 | return protoreflect.EnumNumber(x) 117 | } 118 | 119 | // Deprecated: Use ClosedEnum.Descriptor instead. 120 | func (ClosedEnum) EnumDescriptor() ([]byte, []int) { 121 | return file_buf_protoyaml_test_v1_editions_proto_rawDescGZIP(), []int{1} 122 | } 123 | 124 | type EditionsTest struct { 125 | state protoimpl.MessageState `protogen:"open.v1"` 126 | Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` 127 | Nested *EditionsTest_Nested `protobuf:"group,2,opt,name=Nested,json=nested" json:"nested,omitempty"` 128 | Enum OpenEnum `protobuf:"varint,3,opt,name=enum,enum=buf.protoyaml.test.v1.OpenEnum" json:"enum,omitempty"` 129 | unknownFields protoimpl.UnknownFields 130 | sizeCache protoimpl.SizeCache 131 | } 132 | 133 | func (x *EditionsTest) Reset() { 134 | *x = EditionsTest{} 135 | mi := &file_buf_protoyaml_test_v1_editions_proto_msgTypes[0] 136 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 137 | ms.StoreMessageInfo(mi) 138 | } 139 | 140 | func (x *EditionsTest) String() string { 141 | return protoimpl.X.MessageStringOf(x) 142 | } 143 | 144 | func (*EditionsTest) ProtoMessage() {} 145 | 146 | func (x *EditionsTest) ProtoReflect() protoreflect.Message { 147 | mi := &file_buf_protoyaml_test_v1_editions_proto_msgTypes[0] 148 | if x != nil { 149 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 150 | if ms.LoadMessageInfo() == nil { 151 | ms.StoreMessageInfo(mi) 152 | } 153 | return ms 154 | } 155 | return mi.MessageOf(x) 156 | } 157 | 158 | // Deprecated: Use EditionsTest.ProtoReflect.Descriptor instead. 159 | func (*EditionsTest) Descriptor() ([]byte, []int) { 160 | return file_buf_protoyaml_test_v1_editions_proto_rawDescGZIP(), []int{0} 161 | } 162 | 163 | func (x *EditionsTest) GetName() string { 164 | if x != nil && x.Name != nil { 165 | return *x.Name 166 | } 167 | return "" 168 | } 169 | 170 | func (x *EditionsTest) GetNested() *EditionsTest_Nested { 171 | if x != nil { 172 | return x.Nested 173 | } 174 | return nil 175 | } 176 | 177 | func (x *EditionsTest) GetEnum() OpenEnum { 178 | if x != nil { 179 | return x.Enum 180 | } 181 | return OpenEnum_OPEN_ENUM_UNSPECIFIED 182 | } 183 | 184 | type EditionsTest_Nested struct { 185 | state protoimpl.MessageState `protogen:"open.v1"` 186 | Ids []int64 `protobuf:"varint,1,rep,name=ids" json:"ids,omitempty"` 187 | unknownFields protoimpl.UnknownFields 188 | sizeCache protoimpl.SizeCache 189 | } 190 | 191 | func (x *EditionsTest_Nested) Reset() { 192 | *x = EditionsTest_Nested{} 193 | mi := &file_buf_protoyaml_test_v1_editions_proto_msgTypes[1] 194 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 195 | ms.StoreMessageInfo(mi) 196 | } 197 | 198 | func (x *EditionsTest_Nested) String() string { 199 | return protoimpl.X.MessageStringOf(x) 200 | } 201 | 202 | func (*EditionsTest_Nested) ProtoMessage() {} 203 | 204 | func (x *EditionsTest_Nested) ProtoReflect() protoreflect.Message { 205 | mi := &file_buf_protoyaml_test_v1_editions_proto_msgTypes[1] 206 | if x != nil { 207 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 208 | if ms.LoadMessageInfo() == nil { 209 | ms.StoreMessageInfo(mi) 210 | } 211 | return ms 212 | } 213 | return mi.MessageOf(x) 214 | } 215 | 216 | // Deprecated: Use EditionsTest_Nested.ProtoReflect.Descriptor instead. 217 | func (*EditionsTest_Nested) Descriptor() ([]byte, []int) { 218 | return file_buf_protoyaml_test_v1_editions_proto_rawDescGZIP(), []int{0, 0} 219 | } 220 | 221 | func (x *EditionsTest_Nested) GetIds() []int64 { 222 | if x != nil { 223 | return x.Ids 224 | } 225 | return nil 226 | } 227 | 228 | var File_buf_protoyaml_test_v1_editions_proto protoreflect.FileDescriptor 229 | 230 | const file_buf_protoyaml_test_v1_editions_proto_rawDesc = "" + 231 | "\n" + 232 | "$buf/protoyaml/test/v1/editions.proto\x12\x15buf.protoyaml.test.v1\"\xd3\x01\n" + 233 | "\fEditionsTest\x12\x19\n" + 234 | "\x04name\x18\x01 \x01(\tB\x05\xaa\x01\x02\b\x03R\x04name\x12I\n" + 235 | "\x06nested\x18\x02 \x01(\v2*.buf.protoyaml.test.v1.EditionsTest.NestedB\x05\xaa\x01\x02(\x02R\x06nested\x12:\n" + 236 | "\x04enum\x18\x03 \x01(\x0e2\x1f.buf.protoyaml.test.v1.OpenEnumB\x05\xaa\x01\x02\b\x02R\x04enum\x1a!\n" + 237 | "\x06Nested\x12\x17\n" + 238 | "\x03ids\x18\x01 \x03(\x03B\x05\xaa\x01\x02\x18\x02R\x03ids*%\n" + 239 | "\bOpenEnum\x12\x19\n" + 240 | "\x15OPEN_ENUM_UNSPECIFIED\x10\x00*/\n" + 241 | "\n" + 242 | "ClosedEnum\x12\x1b\n" + 243 | "\x17CLOSED_ENUM_UNSPECIFIED\x10\x00\x1a\x04:\x02\x10\x02B\xe9\x01\n" + 244 | "\x19com.buf.protoyaml.test.v1B\rEditionsProtoP\x01ZFbuf.build/go/protoyaml/internal/gen/proto/buf/protoyaml/test/v1;testv1\xa2\x02\x03BPT\xaa\x02\x15Buf.Protoyaml.Test.V1\xca\x02\x15Buf\\Protoyaml\\Test\\V1\xe2\x02!Buf\\Protoyaml\\Test\\V1\\GPBMetadata\xea\x02\x18Buf::Protoyaml::Test::V1b\beditionsp\xe8\a" 245 | 246 | var ( 247 | file_buf_protoyaml_test_v1_editions_proto_rawDescOnce sync.Once 248 | file_buf_protoyaml_test_v1_editions_proto_rawDescData []byte 249 | ) 250 | 251 | func file_buf_protoyaml_test_v1_editions_proto_rawDescGZIP() []byte { 252 | file_buf_protoyaml_test_v1_editions_proto_rawDescOnce.Do(func() { 253 | file_buf_protoyaml_test_v1_editions_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_editions_proto_rawDesc), len(file_buf_protoyaml_test_v1_editions_proto_rawDesc))) 254 | }) 255 | return file_buf_protoyaml_test_v1_editions_proto_rawDescData 256 | } 257 | 258 | var file_buf_protoyaml_test_v1_editions_proto_enumTypes = make([]protoimpl.EnumInfo, 2) 259 | var file_buf_protoyaml_test_v1_editions_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 260 | var file_buf_protoyaml_test_v1_editions_proto_goTypes = []any{ 261 | (OpenEnum)(0), // 0: buf.protoyaml.test.v1.OpenEnum 262 | (ClosedEnum)(0), // 1: buf.protoyaml.test.v1.ClosedEnum 263 | (*EditionsTest)(nil), // 2: buf.protoyaml.test.v1.EditionsTest 264 | (*EditionsTest_Nested)(nil), // 3: buf.protoyaml.test.v1.EditionsTest.Nested 265 | } 266 | var file_buf_protoyaml_test_v1_editions_proto_depIdxs = []int32{ 267 | 3, // 0: buf.protoyaml.test.v1.EditionsTest.nested:type_name -> buf.protoyaml.test.v1.EditionsTest.Nested 268 | 0, // 1: buf.protoyaml.test.v1.EditionsTest.enum:type_name -> buf.protoyaml.test.v1.OpenEnum 269 | 2, // [2:2] is the sub-list for method output_type 270 | 2, // [2:2] is the sub-list for method input_type 271 | 2, // [2:2] is the sub-list for extension type_name 272 | 2, // [2:2] is the sub-list for extension extendee 273 | 0, // [0:2] is the sub-list for field type_name 274 | } 275 | 276 | func init() { file_buf_protoyaml_test_v1_editions_proto_init() } 277 | func file_buf_protoyaml_test_v1_editions_proto_init() { 278 | if File_buf_protoyaml_test_v1_editions_proto != nil { 279 | return 280 | } 281 | type x struct{} 282 | out := protoimpl.TypeBuilder{ 283 | File: protoimpl.DescBuilder{ 284 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 285 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_buf_protoyaml_test_v1_editions_proto_rawDesc), len(file_buf_protoyaml_test_v1_editions_proto_rawDesc)), 286 | NumEnums: 2, 287 | NumMessages: 2, 288 | NumExtensions: 0, 289 | NumServices: 0, 290 | }, 291 | GoTypes: file_buf_protoyaml_test_v1_editions_proto_goTypes, 292 | DependencyIndexes: file_buf_protoyaml_test_v1_editions_proto_depIdxs, 293 | EnumInfos: file_buf_protoyaml_test_v1_editions_proto_enumTypes, 294 | MessageInfos: file_buf_protoyaml_test_v1_editions_proto_msgTypes, 295 | }.Build() 296 | File_buf_protoyaml_test_v1_editions_proto = out.File 297 | file_buf_protoyaml_test_v1_editions_proto_goTypes = nil 298 | file_buf_protoyaml_test_v1_editions_proto_depIdxs = nil 299 | } 300 | -------------------------------------------------------------------------------- /internal/testdata/basic.proto3test.txt: -------------------------------------------------------------------------------- 1 | internal/testdata/basic.proto3test.yaml:7:18 expected bool, got "1" 2 | 7 | - single_bool: 1 3 | 7 | .................^ 4 | 5 | internal/testdata/basic.proto3test.yaml:8:18 expected bool, got "0" 6 | 8 | - single_bool: 0 7 | 8 | .................^ 8 | 9 | internal/testdata/basic.proto3test.yaml:9:18 expected tag !!bool, got !!str 10 | 9 | - single_bool: "true" 11 | 9 | .................^ 12 | 13 | internal/testdata/basic.proto3test.yaml:10:18 expected tag !!bool, got !!str 14 | 10 | - single_bool: "false" 15 | 10 | .................^ 16 | 17 | internal/testdata/basic.proto3test.yaml:11:18 expected bool, got "True" 18 | 11 | - single_bool: True 19 | 11 | .................^ 20 | 21 | internal/testdata/basic.proto3test.yaml:12:18 expected bool, got "False" 22 | 12 | - single_bool: False 23 | 12 | .................^ 24 | 25 | internal/testdata/basic.proto3test.yaml:13:18 expected bool, got "TRUE" 26 | 13 | - single_bool: TRUE 27 | 13 | .................^ 28 | 29 | internal/testdata/basic.proto3test.yaml:14:18 expected bool, got "FALSE" 30 | 14 | - single_bool: FALSE 31 | 14 | .................^ 32 | 33 | internal/testdata/basic.proto3test.yaml:15:18 expected bool, got "yes" 34 | 15 | - single_bool: yes 35 | 15 | .................^ 36 | 37 | internal/testdata/basic.proto3test.yaml:16:18 expected bool, got "no" 38 | 16 | - single_bool: no 39 | 16 | .................^ 40 | 41 | internal/testdata/basic.proto3test.yaml:17:18 expected scalar, got sequence 42 | 17 | - single_bool: [] 43 | 17 | .................^ 44 | 45 | internal/testdata/basic.proto3test.yaml:18:18 expected scalar, got mapping 46 | 18 | - single_bool: {} 47 | 18 | .................^ 48 | 49 | internal/testdata/basic.proto3test.yaml:25:19 integer is too large: > 2147483647 50 | 25 | - single_int32: 2147483648 51 | 25 | ..................^ 52 | 53 | internal/testdata/basic.proto3test.yaml:26:19 integer is too small: < -2147483648 54 | 26 | - single_int32: -2147483649 55 | 26 | ..................^ 56 | 57 | internal/testdata/basic.proto3test.yaml:29:19 integer is too large: > 2147483647 58 | 29 | - single_int32: 0X80000000 59 | 29 | ..................^ 60 | 61 | internal/testdata/basic.proto3test.yaml:30:19 integer is too small: < -2147483648 62 | 30 | - single_int32: -0x80000001 63 | 30 | ..................^ 64 | 65 | internal/testdata/basic.proto3test.yaml:33:19 integer is too large: > 2147483647 66 | 33 | - single_int32: 0O20000000000 67 | 33 | ..................^ 68 | 69 | internal/testdata/basic.proto3test.yaml:34:19 integer is too small: < -2147483648 70 | 34 | - single_int32: -0o20000000001 71 | 34 | ..................^ 72 | 73 | internal/testdata/basic.proto3test.yaml:37:19 integer is too large: > 2147483647 74 | 37 | - single_int32: 0B10000000000000000000000000000000 75 | 37 | ..................^ 76 | 77 | internal/testdata/basic.proto3test.yaml:38:19 integer is too small: < -2147483648 78 | 38 | - single_int32: -0b10000000000000000000000000000001 79 | 38 | ..................^ 80 | 81 | internal/testdata/basic.proto3test.yaml:39:19 invalid integer: precision loss 82 | 39 | - single_int32: 1.5 83 | 39 | ..................^ 84 | 85 | internal/testdata/basic.proto3test.yaml:42:19 invalid integer: precision loss 86 | 42 | - single_int32: 5.0e-1 87 | 42 | ..................^ 88 | 89 | internal/testdata/basic.proto3test.yaml:48:19 integer is too large: > 9223372036854775807 90 | 48 | - single_int64: 9223372036854775808 91 | 48 | ..................^ 92 | 93 | internal/testdata/basic.proto3test.yaml:49:19 integer is too small: < -9223372036854775808 94 | 49 | - single_int64: -9223372036854775809 95 | 49 | ..................^ 96 | 97 | internal/testdata/basic.proto3test.yaml:51:19 invalid integer: precision loss 98 | 51 | - single_int64: 9007199254740992.0 99 | 51 | ..................^ 100 | 101 | internal/testdata/basic.proto3test.yaml:52:19 invalid integer: strconv.ParseUint: parsing "-1": invalid syntax 102 | 52 | - single_int32: --1 103 | 52 | ..................^ 104 | 105 | internal/testdata/basic.proto3test.yaml:53:19 invalid integer: invalid number, expected digit 106 | 53 | - single_int32: ---1 107 | 53 | ..................^ 108 | 109 | internal/testdata/basic.proto3test.yaml:54:19 invalid integer: strconv.ParseUint: parsing "inf": invalid syntax 110 | 54 | - single_int32: inf 111 | 54 | ..................^ 112 | 113 | internal/testdata/basic.proto3test.yaml:55:19 invalid integer: invalid number, expected digit 114 | 55 | - single_int32: .inf 115 | 55 | ..................^ 116 | 117 | internal/testdata/basic.proto3test.yaml:56:19 invalid integer: invalid number, expected digit 118 | 56 | - single_int32: -.inf 119 | 56 | ..................^ 120 | 121 | internal/testdata/basic.proto3test.yaml:57:19 invalid integer: invalid number, expected digit 122 | 57 | - single_int32: .nan 123 | 57 | ..................^ 124 | 125 | internal/testdata/basic.proto3test.yaml:58:20 invalid integer: strconv.ParseUint: parsing "-1": invalid syntax 126 | 58 | - single_uint32: -1 127 | 58 | ...................^ 128 | 129 | internal/testdata/basic.proto3test.yaml:63:20 integer is too large: > 4294967295 130 | 63 | - single_uint32: 4294967296 131 | 63 | ...................^ 132 | 133 | internal/testdata/basic.proto3test.yaml:65:20 invalid integer: precision loss 134 | 65 | - single_uint64: 18446744073709551616 135 | 65 | ...................^ 136 | 137 | internal/testdata/basic.proto3test.yaml:71:19 invalid float: strconv.ParseFloat: parsing "1.7014118346046923e+39": value out of range 138 | 71 | - single_float: 1.7014118346046923e+39 139 | 71 | ..................^ 140 | 141 | internal/testdata/basic.proto3test.yaml:83:20 expected scalar, got sequence 142 | 83 | - single_string: [] 143 | 83 | ...................^ 144 | 145 | internal/testdata/basic.proto3test.yaml:84:20 expected scalar, got mapping 146 | 84 | - single_string: {} 147 | 84 | ...................^ 148 | 149 | internal/testdata/basic.proto3test.yaml:87:19 invalid base64: illegal base64 data at input byte 3 150 | 87 | - single_bytes: bad base64 151 | 87 | ..................^ 152 | 153 | internal/testdata/basic.proto3test.yaml:95:22 unknown enum value "UNKNOWN", expected one of [FOO BAR BAZ] 154 | 95 | - standalone_enum: UNKNOWN 155 | 95 | .....................^ 156 | 157 | internal/testdata/basic.proto3test.yaml:97:22 unknown enum value "foo", expected one of [FOO BAR BAZ] 158 | 97 | - standalone_enum: foo 159 | 97 | .....................^ 160 | 161 | internal/testdata/basic.proto3test.yaml:98:21 expected sequence, got scalar 162 | 98 | - repeated_int32: 1 163 | 98 | ....................^ 164 | 165 | internal/testdata/basic.proto3test.yaml:100:30 invalid integer: invalid number, expected digit 166 | 100 | - repeated_int32: [1, "1", hi] 167 | 100 | .............................^ 168 | 169 | internal/testdata/basic.proto3test.yaml:101:21 expected sequence, got mapping 170 | 101 | - repeated_int32: {} 171 | 101 | ....................^ 172 | 173 | internal/testdata/basic.proto3test.yaml:102:22 expected scalar, got sequence 174 | 102 | - repeated_int32: [[]] 175 | 102 | .....................^ 176 | 177 | internal/testdata/basic.proto3test.yaml:103:22 expected scalar, got sequence 178 | 103 | - repeated_int32: [[1]] 179 | 103 | .....................^ 180 | 181 | internal/testdata/basic.proto3test.yaml:104:25 expected fields for bufext.cel.expr.conformance.proto3.TestAllTypes.NestedMessage, got scalar 182 | 104 | - standalone_message: 1 183 | 104 | ........................^ 184 | 185 | internal/testdata/basic.proto3test.yaml:105:25 expected fields for bufext.cel.expr.conformance.proto3.TestAllTypes.NestedMessage, got sequence 186 | 105 | - standalone_message: [] 187 | 105 | ........................^ 188 | 189 | internal/testdata/basic.proto3test.yaml:107:22 invalid duration: missing unit, expected one of [h m s ms us ns] 190 | 107 | - single_duration: 1 191 | 107 | .....................^ 192 | 193 | internal/testdata/basic.proto3test.yaml:110:22 invalid duration: fractional nanos 194 | 110 | - single_duration: 1.0123456789s 195 | 110 | .....................^ 196 | 197 | internal/testdata/basic.proto3test.yaml:111:22 invalid number, expected digit 198 | 111 | - single_duration: As 199 | 111 | .....................^ 200 | 201 | internal/testdata/basic.proto3test.yaml:112:22 invalid number, expected digit 202 | 112 | - single_duration: A.1s 203 | 112 | .....................^ 204 | 205 | internal/testdata/basic.proto3test.yaml:113:22 invalid duration: missing unit, expected one of [h m s ms us ns] 206 | 113 | - single_duration: 1.1.1s 207 | 113 | .....................^ 208 | 209 | internal/testdata/basic.proto3test.yaml:114:22 invalid duration: unknown unit, expected one of [h m s ms us ns] 210 | 114 | - single_duration: 1.Bs 211 | 114 | .....................^ 212 | 213 | internal/testdata/basic.proto3test.yaml:119:23 invalid timestamp: before 0001-01-01T00:00:00Z 214 | 119 | - single_timestamp: 0000-01-01T00:00:00Z 215 | 119 | ......................^ 216 | 217 | internal/testdata/basic.proto3test.yaml:121:23 invalid timestamp: parsing time "9999-12-31T23:59:60Z": second out of range 218 | 121 | - single_timestamp: 9999-12-31T23:59:60Z 219 | 121 | ......................^ 220 | 221 | internal/testdata/basic.proto3test.yaml:125:23 invalid timestamp: parsing time "10" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "10" as "2006" 222 | 125 | - single_timestamp: 10 223 | 125 | ......................^ 224 | 225 | internal/testdata/basic.proto3test.yaml:126:23 invalid timestamp: parsing time "hello" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "hello" as "2006" 226 | 126 | - single_timestamp: hello 227 | 126 | ......................^ 228 | 229 | internal/testdata/basic.proto3test.yaml:130:23 expected fields for google.protobuf.Timestamp, got sequence 230 | 130 | - single_timestamp: [] 231 | 130 | ......................^ 232 | 233 | internal/testdata/basic.proto3test.yaml:135:7 unknown field "@type", expected one of [value] 234 | 135 | "@type": type.googleapis.com/google.protobuf.Int32Value 235 | 135 | ......^ 236 | 237 | internal/testdata/basic.proto3test.yaml:142:21 invalid integer: integer is too large 238 | 142 | - single_fixed64: 1000Ei 239 | 142 | ....................^ 240 | 241 | internal/testdata/basic.proto3test.yaml:145:19 integer is too small: < -2147483648 242 | 145 | - single_int32: -1Ti 243 | 145 | ..................^ 244 | 245 | internal/testdata/basic.proto3test.yaml:146:19 invalid integer: invalid bytes: unknown unit, expected one of [k M G T P E Ki Mi Gi Ti Pi Ei] 246 | 146 | - single_int32: 1Ai 247 | 146 | ..................^ 248 | 249 | internal/testdata/basic.proto3test.yaml:147:19 invalid integer: precision loss 250 | 147 | - single_int32: 1.1 251 | 147 | ..................^ 252 | 253 | internal/testdata/basic.proto3test.yaml:148:19 invalid integer: strconv.ParseUint: parsing "1Mi1Ki": invalid syntax 254 | 148 | - single_int32: 1Mi1Ki 255 | 148 | ..................^ 256 | 257 | internal/testdata/basic.proto3test.yaml:150:21 invalid integer: expected number 258 | 150 | - single_fixed64: "" 259 | 150 | ....................^ 260 | 261 | internal/testdata/basic.proto3test.yaml:151:22 unknown enum value "1k", expected one of [FOO BAR BAZ] 262 | 151 | - standalone_enum: 1k 263 | 151 | .....................^ 264 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2023 Buf Technologies, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /protoyaml_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protoyaml 16 | 17 | import ( 18 | "fmt" 19 | "reflect" 20 | "strconv" 21 | "testing" 22 | 23 | "buf.build/go/protoyaml/internal/gen/proto/bufext/cel/expr/conformance/proto3" 24 | "buf.build/go/protoyaml/internal/protoyamltest" 25 | "github.com/google/go-cmp/cmp" 26 | "github.com/stretchr/testify/require" 27 | "google.golang.org/protobuf/encoding/protojson" 28 | "google.golang.org/protobuf/reflect/protoreflect" 29 | "google.golang.org/protobuf/testing/protocmp" 30 | "google.golang.org/protobuf/types/dynamicpb" 31 | "google.golang.org/protobuf/types/known/anypb" 32 | "google.golang.org/protobuf/types/known/durationpb" 33 | "google.golang.org/protobuf/types/known/structpb" 34 | "google.golang.org/protobuf/types/known/timestamppb" 35 | "gopkg.in/yaml.v3" 36 | ) 37 | 38 | func TestParseFieldPath(t *testing.T) { 39 | t.Parallel() 40 | for i, testCase := range []struct { 41 | Path string 42 | Expect []string 43 | }{ 44 | {Path: "", Expect: nil}, 45 | {Path: "foo", Expect: []string{"foo"}}, 46 | {Path: "foo.bar", Expect: []string{"foo", "bar"}}, 47 | {Path: "foo[0]", Expect: []string{"foo", "0"}}, 48 | {Path: "foo[0].bar", Expect: []string{"foo", "0", "bar"}}, 49 | {Path: "foo[0][1]", Expect: []string{"foo", "0", "1"}}, 50 | {Path: "foo.0.1.bar", Expect: []string{"foo", "0", "1", "bar"}}, 51 | {Path: "foo.bar[0]", Expect: []string{"foo", "bar", "0"}}, 52 | {Path: "foo.bar[0].baz", Expect: []string{"foo", "bar", "0", "baz"}}, 53 | {Path: `foo["bar"].baz`, Expect: []string{"foo", "bar", "baz"}}, 54 | {Path: `foo["bar"].baz[0]`, Expect: []string{"foo", "bar", "baz", "0"}}, 55 | {Path: `foo["b\"ar"].baz[0]`, Expect: []string{"foo", "b\"ar", "baz", "0"}}, 56 | {Path: `foo["b.ar"].baz`, Expect: []string{"foo", "b.ar", "baz"}}, 57 | } { 58 | t.Run(strconv.Itoa(i), func(t *testing.T) { 59 | t.Parallel() 60 | result, err := parseFieldPath(testCase.Path) 61 | if err != nil { 62 | t.Fatal(err) 63 | } 64 | if !reflect.DeepEqual(result, testCase.Expect) { 65 | t.Fatalf("Expected %v, got %v", testCase.Expect, result) 66 | } 67 | }) 68 | } 69 | } 70 | 71 | // Ensure the value can round trip as a dynamic message. 72 | func testDynamicRoundTrip(t *testing.T, desc protoreflect.MessageDescriptor, data []byte) { 73 | t.Helper() 74 | dynval := dynamicpb.NewMessage(desc) 75 | if err := Unmarshal(data, dynval); err != nil { 76 | t.Fatal(err) 77 | } 78 | dyndata, err := Marshal(dynval) 79 | if err != nil { 80 | t.Fatal(err) 81 | } 82 | if string(data) != string(dyndata) { 83 | t.Fatalf("Expected %s, got %s", string(data), string(dyndata)) 84 | } 85 | } 86 | 87 | func TestDuration_DynamicWithNanos(t *testing.T) { 88 | t.Parallel() 89 | for _, testCase := range []*durationpb.Duration{ 90 | {Seconds: 3600, Nanos: 1001}, 91 | {Seconds: -3600, Nanos: -1001}, 92 | {Seconds: 3600}, 93 | {Seconds: -3600}, 94 | {Nanos: 1001}, 95 | {Nanos: -1001}, 96 | } { 97 | data, err := Marshal(testCase) 98 | if err != nil { 99 | t.Fatal(err) 100 | } 101 | actual := &durationpb.Duration{} 102 | if err := Unmarshal(data, actual); err != nil { 103 | t.Fatal(err) 104 | } 105 | if !reflect.DeepEqual(testCase, actual) { 106 | t.Fatalf("Expected %v, got %v", testCase, actual) 107 | } 108 | testDynamicRoundTrip(t, testCase.ProtoReflect().Descriptor(), data) 109 | } 110 | } 111 | 112 | func TestTimestamp_DynamicWithNanos(t *testing.T) { 113 | t.Parallel() 114 | for _, testCase := range []*timestamppb.Timestamp{ 115 | {Seconds: 3600, Nanos: 1001}, 116 | {Seconds: -3600, Nanos: 1001}, 117 | } { 118 | data, err := Marshal(testCase) 119 | if err != nil { 120 | t.Fatal(err) 121 | } 122 | actual := ×tamppb.Timestamp{} 123 | if err := Unmarshal(data, actual); err != nil { 124 | t.Fatal(err) 125 | } 126 | if !reflect.DeepEqual(testCase, actual) { 127 | t.Fatalf("Expected %v, got %v", testCase, actual) 128 | } 129 | testDynamicRoundTrip(t, testCase.ProtoReflect().Descriptor(), data) 130 | } 131 | } 132 | 133 | func testValueDynamicRoundTrip(t *testing.T, data string) { 134 | t.Helper() 135 | val := &structpb.Value{} 136 | testDynamicRoundTrip(t, val.ProtoReflect().Descriptor(), []byte(data)) 137 | } 138 | 139 | func TestValue_Dynamic(t *testing.T) { 140 | t.Parallel() 141 | testValueDynamicRoundTrip(t, "null\n") 142 | testValueDynamicRoundTrip(t, "true\n") 143 | testValueDynamicRoundTrip(t, "false\n") 144 | testValueDynamicRoundTrip(t, "1\n") 145 | testValueDynamicRoundTrip(t, "\"1\"\n") 146 | testValueDynamicRoundTrip(t, "foo\n") 147 | testValueDynamicRoundTrip(t, "[]\n") 148 | testValueDynamicRoundTrip(t, "{}\n") 149 | testValueDynamicRoundTrip(t, "foo: bar\n") 150 | testValueDynamicRoundTrip(t, "foo: 1\n") 151 | testValueDynamicRoundTrip(t, "foo: \"1\"\n") 152 | testValueDynamicRoundTrip(t, "foo: true\n") 153 | testValueDynamicRoundTrip(t, "foo: false\n") 154 | testValueDynamicRoundTrip(t, "foo: null\n") 155 | testValueDynamicRoundTrip(t, "foo: []\n") 156 | testValueDynamicRoundTrip(t, "foo: {}\n") 157 | testValueDynamicRoundTrip(t, "foo:\n - 1\n") 158 | } 159 | 160 | func TestListValue_Dynamic(t *testing.T) { 161 | t.Parallel() 162 | val := &structpb.ListValue{ 163 | Values: []*structpb.Value{ 164 | {Kind: &structpb.Value_NullValue{}}, 165 | {Kind: &structpb.Value_NumberValue{NumberValue: 1}}, 166 | {Kind: &structpb.Value_StringValue{StringValue: "foo"}}, 167 | }, 168 | } 169 | data, err := Marshal(val) 170 | if err != nil { 171 | t.Fatal(err) 172 | } 173 | if string(data) != "- null\n- 1\n- foo\n" { 174 | t.Fatalf("Expected - null\n- 1\n- foo, got %s", string(data)) 175 | } 176 | actual := &structpb.ListValue{} 177 | if err := Unmarshal(data, actual); err != nil { 178 | t.Fatal(err) 179 | } 180 | dynval := dynamicpb.NewMessage(val.ProtoReflect().Descriptor()) 181 | if err := Unmarshal(data, dynval); err != nil { 182 | t.Fatal(err) 183 | } 184 | dyndata, err := Marshal(dynval) 185 | if err != nil { 186 | t.Fatal(err) 187 | } 188 | if string(data) != string(dyndata) { 189 | t.Fatalf("Expected %s, got %s", string(data), string(dyndata)) 190 | } 191 | } 192 | 193 | // See https://github.com/go-yaml/yaml/issues/1004 194 | // 195 | // Update combinatorial tests to include this case again when fixed. 196 | func TestYamlNewLineMaps(t *testing.T) { 197 | t.Parallel() 198 | value := map[string]string{ 199 | "\n": "\n", 200 | } 201 | data, err := yaml.Marshal(value) 202 | if err != nil { 203 | t.Fatal(err) 204 | } 205 | // Should be `"\n": "\n"`, but its garbled. 206 | if string(data) != "? |4+\n: |4+\n" { 207 | t.Fatalf("Expected garbled output, got %s", string(data)) 208 | } 209 | } 210 | 211 | // Test that non-zero null values don't round trip. 212 | func TestNullValueEnum(t *testing.T) { 213 | t.Parallel() 214 | data, err := Marshal(&proto3.TestAllTypes{ 215 | RepeatedNullValue: []structpb.NullValue{ 216 | 1, 217 | }, 218 | }) 219 | if err != nil { 220 | t.Fatal(err) 221 | } 222 | if string(data) != "repeatedNullValue:\n - null\n" { 223 | t.Fatalf("Expected %#v, got %#v", "repeatedNullValue:\n - null\n", string(data)) 224 | } 225 | actual := &proto3.TestAllTypes{} 226 | if err := Unmarshal(data, actual); err != nil { 227 | t.Fatal(err) 228 | } 229 | if len(actual.GetRepeatedNullValue()) != 1 { 230 | t.Fatalf("Expected 1, got %d", len(actual.GetRepeatedNullValue())) 231 | } 232 | if actual.GetRepeatedNullValue()[0] != structpb.NullValue_NULL_VALUE { 233 | t.Fatalf("Expected %v, got %v", structpb.NullValue_NULL_VALUE, actual.GetRepeatedNullValue()[0]) 234 | } 235 | } 236 | 237 | func TestInfNanIntegers(t *testing.T) { 238 | t.Parallel() 239 | for _, testCase := range []string{ 240 | "single_int32: inf", 241 | "single_int32: -inf", 242 | "single_int32: nan", 243 | "single_int64: Infinity", 244 | "single_int64: -Infinity", 245 | "single_int64: NaN", 246 | } { 247 | t.Run(testCase, func(t *testing.T) { 248 | t.Parallel() 249 | data := []byte(testCase) 250 | actual := &proto3.TestAllTypes{} 251 | err := Unmarshal(data, actual) 252 | require.ErrorContains(t, err, "invalid syntax") 253 | }) 254 | } 255 | } 256 | 257 | func TestAnyValue(t *testing.T) { 258 | t.Parallel() 259 | for _, testCase := range []string{ 260 | "{}", "1", "[1, \"hi\"]", 261 | } { 262 | t.Run(testCase, func(t *testing.T) { 263 | t.Parallel() 264 | data := []byte(`{"@type": "type.googleapis.com/google.protobuf.Value", "value": ` + testCase + `}`) 265 | yamlAnyVal := &anypb.Any{} 266 | if err := Unmarshal(data, yamlAnyVal); err != nil { 267 | t.Fatal(err) 268 | } 269 | jsonAnyVal := &anypb.Any{} 270 | if err := protojson.Unmarshal(data, jsonAnyVal); err != nil { 271 | t.Fatal(err) 272 | } 273 | actualYaml := &structpb.Value{} 274 | if err := yamlAnyVal.UnmarshalTo(actualYaml); err != nil { 275 | t.Fatal(err) 276 | } 277 | actualJSON := &structpb.Value{} 278 | if err := jsonAnyVal.UnmarshalTo(actualJSON); err != nil { 279 | t.Fatal(err) 280 | } 281 | if diff := cmp.Diff(actualJSON, actualYaml, protocmp.Transform()); diff != "" { 282 | t.Errorf("Unexpected diff:\n%s", diff) 283 | } 284 | }) 285 | } 286 | } 287 | 288 | func TestCombinatorial(t *testing.T) { 289 | t.Parallel() 290 | cases := protoyamltest.InterestingTestValues() 291 | for i, c := range cases { 292 | t.Run(strconv.Itoa(i), func(t *testing.T) { 293 | t.Parallel() 294 | testRoundTrip(t, c) 295 | }) 296 | } 297 | } 298 | 299 | func TestFuzz(t *testing.T) { 300 | t.Parallel() 301 | for i := range int64(100) { 302 | t.Run(strconv.FormatInt(i, 10), func(t *testing.T) { 303 | t.Parallel() 304 | msg := &proto3.TestAllTypes{} 305 | protoyamltest.PopulateMessage(msg, i) 306 | 307 | data, err := Marshal(msg) 308 | if err != nil { 309 | t.Fatal(err) 310 | } 311 | roundTrip := &proto3.TestAllTypes{} 312 | err = Unmarshal(data, roundTrip) 313 | if err != nil { 314 | t.Fatal(err) 315 | } 316 | diff := cmp.Diff(msg, roundTrip, protocmp.Transform(), 317 | cmp.Comparer(func(x, y float32) bool { 318 | return fmt.Sprintf("%f", x) == fmt.Sprintf("%f", y) 319 | }), 320 | cmp.Comparer(func(x, y float64) bool { 321 | return fmt.Sprintf("%f", x) == fmt.Sprintf("%f", y) 322 | }), 323 | ) 324 | if diff != "" { 325 | t.Fatal(diff) 326 | } 327 | }) 328 | } 329 | } 330 | 331 | func testRoundTrip(t *testing.T, testCase *proto3.TestAllTypes) { 332 | t.Helper() 333 | t.Run("Default", func(t *testing.T) { 334 | testRoundTripOption(t, testCase, MarshalOptions{}) 335 | }) 336 | t.Run("Alt", func(t *testing.T) { 337 | testRoundTripOption(t, testCase, MarshalOptions{ 338 | UseProtoNames: true, 339 | UseEnumNumbers: true, 340 | }) 341 | }) 342 | } 343 | 344 | func testRoundTripOption(t *testing.T, testCase *proto3.TestAllTypes, encOpt MarshalOptions) { 345 | t.Helper() 346 | // Encode the message as YAML 347 | data, err := encOpt.Marshal(testCase) 348 | if err != nil { 349 | t.Fatal(err) 350 | } 351 | 352 | // Decode the message from Yaml 353 | testUnmarshal(t, testCase, data) 354 | 355 | // Encode the message as JSON 356 | 357 | jsonData, err := protojson.MarshalOptions{ 358 | AllowPartial: encOpt.AllowPartial, 359 | UseProtoNames: encOpt.UseProtoNames, 360 | UseEnumNumbers: encOpt.UseEnumNumbers, 361 | EmitUnpopulated: encOpt.EmitUnpopulated, 362 | Resolver: encOpt.Resolver, 363 | }.Marshal(testCase) 364 | if err != nil { 365 | t.Fatal(err) 366 | } 367 | 368 | // Decode the message from JSON 369 | testUnmarshal(t, testCase, jsonData) 370 | } 371 | 372 | func testUnmarshal(t *testing.T, testCase *proto3.TestAllTypes, data []byte) { 373 | t.Helper() 374 | roundTrip := &proto3.TestAllTypes{} 375 | err := Unmarshal(data, roundTrip) 376 | if err != nil { 377 | t.Fatal(err) 378 | } 379 | 380 | // Compare the two messages 381 | diff := cmp.Diff(testCase, roundTrip, protocmp.Transform(), 382 | cmp.Comparer(func(x, y float32) bool { 383 | return fmt.Sprintf("%f", x) == fmt.Sprintf("%f", y) 384 | }), 385 | cmp.Comparer(func(x, y float64) bool { 386 | return fmt.Sprintf("%f", x) == fmt.Sprintf("%f", y) 387 | })) 388 | if diff != "" { 389 | t.Fatal(diff) 390 | } 391 | } 392 | -------------------------------------------------------------------------------- /internal/protoyamltest/combine.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protoyamltest 16 | 17 | import ( 18 | "math" 19 | 20 | "buf.build/go/protoyaml/internal/gen/proto/bufext/cel/expr/conformance/proto3" 21 | "google.golang.org/protobuf/reflect/protoreflect" 22 | "google.golang.org/protobuf/types/known/anypb" 23 | "google.golang.org/protobuf/types/known/structpb" 24 | "google.golang.org/protobuf/types/known/wrapperspb" 25 | ) 26 | 27 | // InterestingTestValues returns a list of interesting values for testing. 28 | // 29 | // For example extrema, zero values, and other values that exercise edge cases. 30 | func InterestingTestValues() []*proto3.TestAllTypes { 31 | var interestingValues []*proto3.TestAllTypes 32 | for _, value := range []bool{true, false} { 33 | wrapped := &wrapperspb.BoolValue{Value: value} 34 | anyBool, err := anypb.New(wrapped) 35 | if err != nil { 36 | panic(err) 37 | } 38 | interestingValues = append(interestingValues, 39 | &proto3.TestAllTypes{ 40 | SingleBool: value, 41 | }, 42 | &proto3.TestAllTypes{ 43 | RepeatedBool: []bool{value}, 44 | }, 45 | &proto3.TestAllTypes{ 46 | SingleBoolWrapper: wrapped, 47 | }, 48 | &proto3.TestAllTypes{ 49 | RepeatedBool: []bool{value}, 50 | }, 51 | &proto3.TestAllTypes{ 52 | RepeatedBoolWrapper: []*wrapperspb.BoolValue{wrapped}, 53 | }, 54 | &proto3.TestAllTypes{ 55 | MapBoolBool: map[bool]bool{value: value}, 56 | }, 57 | &proto3.TestAllTypes{ 58 | SingleValue: &structpb.Value{Kind: &structpb.Value_BoolValue{BoolValue: value}}, 59 | }, 60 | &proto3.TestAllTypes{ 61 | SingleAny: anyBool, 62 | }, 63 | &proto3.TestAllTypes{ 64 | RepeatedAny: []*anypb.Any{anyBool}, 65 | }, 66 | ) 67 | } 68 | fields := (&proto3.TestAllTypes{}).ProtoReflect().Descriptor().Fields() 69 | for i := range fields.Len() { 70 | interestingValues = append(interestingValues, 71 | interestingFieldValues(fields.Get(i))...) 72 | } 73 | return interestingValues 74 | } 75 | 76 | func interestingMessageFieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 77 | var interestingValues []*proto3.TestAllTypes 78 | switch { 79 | case field.IsList(): 80 | listVal := &proto3.TestAllTypes{} 81 | for j := range 3 { 82 | newVal := listVal.ProtoReflect().Get(field).List().NewElement() 83 | PopulateMessage(newVal.Message().Interface(), int64(j)) 84 | listVal.ProtoReflect().Mutable(field).List().Append(newVal) 85 | } 86 | interestingValues = append(interestingValues, listVal) 87 | case field.IsMap(): 88 | // TODO: populate map 89 | default: 90 | newVal := &proto3.TestAllTypes{} 91 | PopulateMessage(newVal.ProtoReflect().Mutable(field).Message().Interface(), 0) 92 | interestingValues = append(interestingValues, newVal) 93 | } 94 | return interestingValues 95 | } 96 | 97 | func interestingEnumFieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 98 | var interestingValues []*proto3.TestAllTypes 99 | values := interestingEnumValues(field.Enum()) 100 | if field.IsList() { 101 | listVal := &proto3.TestAllTypes{} 102 | for _, value := range values { 103 | listVal.ProtoReflect().Mutable(field).List().Append(protoreflect.ValueOfEnum(value)) 104 | } 105 | interestingValues = append(interestingValues, listVal) 106 | } else { 107 | for _, value := range values { 108 | newVal := &proto3.TestAllTypes{} 109 | newVal.ProtoReflect().Set(field, protoreflect.ValueOfEnum(value)) 110 | interestingValues = append(interestingValues, newVal) 111 | } 112 | } 113 | return interestingValues 114 | } 115 | 116 | func interestingI32FieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 117 | var interestingValues []*proto3.TestAllTypes 118 | values := interestingIntegers(32) 119 | if field.IsList() { 120 | listVal := &proto3.TestAllTypes{} 121 | for _, value := range values { 122 | listVal.ProtoReflect().Mutable(field).List().Append(protoreflect.ValueOfInt32(int32(value))) 123 | } 124 | interestingValues = append(interestingValues, listVal) 125 | } else { 126 | for _, value := range values { 127 | newVal := &proto3.TestAllTypes{} 128 | newVal.ProtoReflect().Set(field, protoreflect.ValueOfInt32(int32(value))) 129 | interestingValues = append(interestingValues, newVal) 130 | } 131 | } 132 | return interestingValues 133 | } 134 | 135 | func interestingI64FieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 136 | var interestingValues []*proto3.TestAllTypes 137 | values := interestingIntegers(64) 138 | if field.IsList() { 139 | listVal := &proto3.TestAllTypes{} 140 | for _, value := range values { 141 | listVal.ProtoReflect().Mutable(field).List().Append(protoreflect.ValueOfInt64(value)) 142 | } 143 | interestingValues = append(interestingValues, listVal) 144 | } else { 145 | for _, value := range values { 146 | newVal := &proto3.TestAllTypes{} 147 | newVal.ProtoReflect().Set(field, protoreflect.ValueOfInt64(value)) 148 | interestingValues = append(interestingValues, newVal) 149 | } 150 | } 151 | return interestingValues 152 | } 153 | 154 | func interestingU32FieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 155 | var interestingValues []*proto3.TestAllTypes 156 | values := interestingUnsigned(32) 157 | if field.IsList() { 158 | listVal := &proto3.TestAllTypes{} 159 | for _, value := range values { 160 | listVal.ProtoReflect().Mutable(field).List().Append(protoreflect.ValueOfUint32(uint32(value))) 161 | } 162 | interestingValues = append(interestingValues, listVal) 163 | } else { 164 | for _, value := range values { 165 | newVal := &proto3.TestAllTypes{} 166 | newVal.ProtoReflect().Set(field, protoreflect.ValueOfUint32(uint32(value))) 167 | interestingValues = append(interestingValues, newVal) 168 | } 169 | } 170 | return interestingValues 171 | } 172 | 173 | func interestingU64FieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 174 | var interestingValues []*proto3.TestAllTypes 175 | values := interestingUnsigned(64) 176 | if field.IsList() { 177 | listVal := &proto3.TestAllTypes{} 178 | for _, value := range values { 179 | listVal.ProtoReflect().Mutable(field).List().Append(protoreflect.ValueOfUint64(value)) 180 | } 181 | interestingValues = append(interestingValues, listVal) 182 | } else { 183 | for _, value := range values { 184 | newVal := &proto3.TestAllTypes{} 185 | newVal.ProtoReflect().Set(field, protoreflect.ValueOfUint64(value)) 186 | interestingValues = append(interestingValues, newVal) 187 | } 188 | } 189 | return interestingValues 190 | } 191 | 192 | func interestingFloatFieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 193 | var interestingValues []*proto3.TestAllTypes 194 | values := interestingFloats(32) 195 | if field.IsList() { 196 | listVal := &proto3.TestAllTypes{} 197 | for _, value := range values { 198 | listVal.ProtoReflect().Mutable(field).List().Append(protoreflect.ValueOfFloat32(float32(value))) 199 | } 200 | interestingValues = append(interestingValues, listVal) 201 | } else { 202 | for _, value := range values { 203 | newVal := &proto3.TestAllTypes{} 204 | newVal.ProtoReflect().Set(field, protoreflect.ValueOfFloat32(float32(value))) 205 | interestingValues = append(interestingValues, newVal) 206 | } 207 | } 208 | return interestingValues 209 | } 210 | 211 | func interestingDoubleFieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 212 | var interestingValues []*proto3.TestAllTypes 213 | values := interestingFloats(64) 214 | if field.IsList() { 215 | listVal := &proto3.TestAllTypes{} 216 | for _, value := range values { 217 | listVal.ProtoReflect().Mutable(field).List().Append(protoreflect.ValueOfFloat64(value)) 218 | } 219 | interestingValues = append(interestingValues, listVal) 220 | } else { 221 | for _, value := range values { 222 | newVal := &proto3.TestAllTypes{} 223 | newVal.ProtoReflect().Set(field, protoreflect.ValueOfFloat64(value)) 224 | interestingValues = append(interestingValues, newVal) 225 | } 226 | } 227 | return interestingValues 228 | } 229 | 230 | func interestingStringFieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 231 | var interestingValues []*proto3.TestAllTypes 232 | values := interestingStrings() 233 | if field.IsList() { 234 | listVal := &proto3.TestAllTypes{} 235 | for _, value := range values { 236 | listVal.ProtoReflect().Mutable(field).List().Append(protoreflect.ValueOfString(value)) 237 | } 238 | interestingValues = append(interestingValues, listVal) 239 | } else { 240 | for _, value := range values { 241 | newVal := &proto3.TestAllTypes{} 242 | newVal.ProtoReflect().Set(field, protoreflect.ValueOfString(value)) 243 | interestingValues = append(interestingValues, newVal) 244 | } 245 | } 246 | return interestingValues 247 | } 248 | 249 | func interestingBytesFieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 250 | var interestingValues []*proto3.TestAllTypes 251 | values := interestingBytes() 252 | if field.IsList() { 253 | listVal := &proto3.TestAllTypes{} 254 | for _, value := range values { 255 | listVal.ProtoReflect().Mutable(field).List().Append(protoreflect.ValueOfBytes(value)) 256 | } 257 | interestingValues = append(interestingValues, listVal) 258 | } else { 259 | for _, value := range values { 260 | newVal := &proto3.TestAllTypes{} 261 | newVal.ProtoReflect().Set(field, protoreflect.ValueOfBytes(value)) 262 | interestingValues = append(interestingValues, newVal) 263 | } 264 | } 265 | return interestingValues 266 | } 267 | 268 | func interestingFieldValues(field protoreflect.FieldDescriptor) []*proto3.TestAllTypes { 269 | switch field.Kind() { 270 | case protoreflect.MessageKind: 271 | return interestingMessageFieldValues(field) 272 | case protoreflect.EnumKind: 273 | return interestingEnumFieldValues(field) 274 | case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: 275 | return interestingI32FieldValues(field) 276 | case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 277 | return interestingI64FieldValues(field) 278 | case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: 279 | return interestingU32FieldValues(field) 280 | case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 281 | return interestingU64FieldValues(field) 282 | case protoreflect.FloatKind: 283 | return interestingFloatFieldValues(field) 284 | case protoreflect.DoubleKind: 285 | return interestingDoubleFieldValues(field) 286 | case protoreflect.StringKind: 287 | return interestingStringFieldValues(field) 288 | case protoreflect.BytesKind: 289 | return interestingBytesFieldValues(field) 290 | } 291 | return nil 292 | } 293 | 294 | func interestingEnumValues(enum protoreflect.EnumDescriptor) []protoreflect.EnumNumber { 295 | values := enum.Values() 296 | var result []protoreflect.EnumNumber 297 | for i := range values.Len() { 298 | result = append(result, values.Get(i).Number()) 299 | } 300 | if enum.FullName() != "google.protobuf.NullValue" { 301 | result = append(result, 0, -1, math.MaxInt32, math.MinInt32) 302 | } 303 | return result 304 | } 305 | 306 | func interestingIntegers(bits int) []int64 { 307 | maxVal := int64(1<<(bits-1) - 1) 308 | minVal := int64(-1 << (bits - 1)) 309 | result := []int64{ 310 | 0, 311 | 1, 312 | -1, 313 | maxVal, 314 | minVal, 315 | } 316 | if bits > 53 { 317 | result = append(result, 1<<53-1, 1<<53, 1<<53+1) 318 | } 319 | return result 320 | } 321 | 322 | func interestingUnsigned(bits int) []uint64 { 323 | result := []uint64{ 324 | 0, 325 | 1, 326 | 1< 53 { 329 | result = append(result, 1<<53-1, 1<<53, 1<<53+1) 330 | } 331 | return result 332 | } 333 | 334 | func interestingFloats(bits uint8) []float64 { 335 | var result []float64 336 | 337 | // Zeros 338 | result = append(result, 1/math.Inf(1), -1/math.Inf(1)) 339 | // NaN 340 | result = append(result, math.NaN()) 341 | 342 | // Ones 343 | result = append(result, 1.0, -1.0) 344 | // Fractions 345 | result = append(result, 0.5, -0.5, 0.25, -0.25, 0.125, -0.125) 346 | // Infinities 347 | result = append(result, math.Inf(1), math.Inf(-1)) 348 | switch bits { 349 | case 32: 350 | // Smallest positive subnormal 351 | result = append(result, float64(math.Float32frombits(0x00000001))) 352 | // Largest subnormal 353 | result = append(result, float64(math.Float32frombits(0x007fffff))) 354 | // Smallest positive normal 355 | result = append(result, float64(math.Float32frombits(0x00800000))) 356 | // Largest normal 357 | result = append(result, float64(math.Float32frombits(0x7f7fffff))) 358 | case 64: 359 | // Smallest positive subnormal 360 | result = append(result, math.Float64frombits(0x0000000000000001)) 361 | // Largest subnormal 362 | result = append(result, math.Float64frombits(0x000fffffffffffff)) 363 | // Smallest positive normal 364 | result = append(result, math.Float64frombits(0x0010000000000000)) 365 | // Largest normal 366 | result = append(result, math.Float64frombits(0x7fefffffffffffff)) 367 | // Max safe integer 368 | result = append(result, math.Float64frombits(0x1fffffffffffff)) 369 | default: 370 | panic("unknown float size") 371 | } 372 | return result 373 | } 374 | 375 | func interestingStrings() []string { 376 | return []string{ 377 | // Empty 378 | "", 379 | // Whitespace 380 | " ", 381 | // "\n", TODO: Uncomment once https://github.com/go-yaml/yaml/issues/1004 is fixed 382 | "\t", 383 | "\r", 384 | // Nonprintable 385 | "\x00", 386 | "\x01", 387 | "\a", 388 | "\b", 389 | "\f", 390 | // Escaped 391 | "\\", 392 | "\\\\", 393 | "\\\"", 394 | "\\'", 395 | "\\a", 396 | "\\b", 397 | "\\f", 398 | // Ascii 399 | "hello", 400 | // Unicode 401 | "你好", 402 | "こんにちは", 403 | "☺☹", 404 | "😀😁", 405 | } 406 | } 407 | 408 | func interestingBytes() [][]byte { 409 | // All the interesting strings 410 | var result [][]byte 411 | for _, s := range interestingStrings() { 412 | result = append(result, []byte(s)) 413 | } 414 | // Invalid UTF-8 415 | result = append(result, []byte{0xff, 0xfe, 0xfd}) 416 | return result 417 | } 418 | -------------------------------------------------------------------------------- /internal/proto/bufext/cel/expr/conformance/proto3/test_all_types.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2024 Buf Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Mostly originally copied from https://github.com/google/cel-spec/blob/ed066e332b7acc3dbf68e65e0001061539d25e83/proto/cel/expr/conformance/proto3/test_all_types.proto. 16 | // See the license at https://github.com/google/cel-spec/blob/ed066e332b7acc3dbf68e65e0001061539d25e83/LICENSE. 17 | 18 | syntax = "proto3"; 19 | 20 | package bufext.cel.expr.conformance.proto3; 21 | 22 | import "google/protobuf/any.proto"; 23 | import "google/protobuf/duration.proto"; 24 | import "google/protobuf/struct.proto"; 25 | import "google/protobuf/timestamp.proto"; 26 | import "google/protobuf/wrappers.proto"; 27 | 28 | option cc_enable_arenas = true; 29 | option go_package = "cel.dev/expr/conformance/proto3"; 30 | option java_multiple_files = true; 31 | option java_outer_classname = "TestAllTypesProto"; 32 | option java_package = "dev.cel.expr.conformance.proto3"; 33 | 34 | // This proto includes every type of field in both singular and repeated 35 | // forms. 36 | message TestAllTypes { 37 | message NestedMessage { 38 | // The field name "b" fails to compile in proto1 because it conflicts with 39 | // a local variable named "b" in one of the generated methods. 40 | // This file needs to compile in proto1 to test backwards-compatibility. 41 | int32 bb = 1; 42 | } 43 | 44 | enum NestedEnum { 45 | FOO = 0; 46 | BAR = 1; 47 | BAZ = 2; 48 | } 49 | 50 | // Singular 51 | int32 single_int32 = 1; 52 | int64 single_int64 = 2; 53 | uint32 single_uint32 = 3; 54 | uint64 single_uint64 = 4; 55 | sint32 single_sint32 = 5; 56 | sint64 single_sint64 = 6; 57 | fixed32 single_fixed32 = 7; 58 | fixed64 single_fixed64 = 8; 59 | sfixed32 single_sfixed32 = 9; 60 | sfixed64 single_sfixed64 = 10; 61 | float single_float = 11; 62 | double single_double = 12; 63 | bool single_bool = 13; 64 | string single_string = 14; 65 | bytes single_bytes = 15; 66 | 67 | // Wellknown. 68 | google.protobuf.Any single_any = 100; 69 | google.protobuf.Duration single_duration = 101; 70 | google.protobuf.Timestamp single_timestamp = 102; 71 | google.protobuf.Struct single_struct = 103; 72 | google.protobuf.Value single_value = 104; 73 | google.protobuf.Int64Value single_int64_wrapper = 105; 74 | google.protobuf.Int32Value single_int32_wrapper = 106; 75 | google.protobuf.DoubleValue single_double_wrapper = 107; 76 | google.protobuf.FloatValue single_float_wrapper = 108; 77 | google.protobuf.UInt64Value single_uint64_wrapper = 109; 78 | google.protobuf.UInt32Value single_uint32_wrapper = 110; 79 | google.protobuf.StringValue single_string_wrapper = 111; 80 | google.protobuf.BoolValue single_bool_wrapper = 112; 81 | google.protobuf.BytesValue single_bytes_wrapper = 113; 82 | google.protobuf.ListValue list_value = 114; 83 | google.protobuf.NullValue null_value = 115; 84 | optional google.protobuf.NullValue optional_null_value = 116; 85 | 86 | // Nested messages 87 | oneof nested_type { 88 | NestedMessage single_nested_message = 21; 89 | NestedEnum single_nested_enum = 22; 90 | } 91 | NestedMessage standalone_message = 23; 92 | NestedEnum standalone_enum = 24; 93 | 94 | // Repeated 95 | repeated int32 repeated_int32 = 31; 96 | repeated int64 repeated_int64 = 32; 97 | repeated uint32 repeated_uint32 = 33; 98 | repeated uint64 repeated_uint64 = 34; 99 | repeated sint32 repeated_sint32 = 35; 100 | repeated sint64 repeated_sint64 = 36; 101 | repeated fixed32 repeated_fixed32 = 37; 102 | repeated fixed64 repeated_fixed64 = 38; 103 | repeated sfixed32 repeated_sfixed32 = 39; 104 | repeated sfixed64 repeated_sfixed64 = 40; 105 | repeated float repeated_float = 41; 106 | repeated double repeated_double = 42; 107 | repeated bool repeated_bool = 43; 108 | repeated string repeated_string = 44; 109 | repeated bytes repeated_bytes = 45; 110 | 111 | // Repeated and nested 112 | repeated NestedMessage repeated_nested_message = 51; 113 | repeated NestedEnum repeated_nested_enum = 52; 114 | repeated string repeated_string_piece = 53 [ctype = STRING_PIECE]; 115 | repeated string repeated_cord = 54 [ctype = CORD]; 116 | repeated NestedMessage repeated_lazy_message = 55 [lazy = true]; 117 | 118 | // Repeated wellknown. 119 | repeated google.protobuf.Any repeated_any = 120; 120 | repeated google.protobuf.Duration repeated_duration = 121; 121 | repeated google.protobuf.Timestamp repeated_timestamp = 122; 122 | repeated google.protobuf.Struct repeated_struct = 123; 123 | repeated google.protobuf.Value repeated_value = 124; 124 | repeated google.protobuf.Int64Value repeated_int64_wrapper = 125; 125 | repeated google.protobuf.Int32Value repeated_int32_wrapper = 126; 126 | repeated google.protobuf.DoubleValue repeated_double_wrapper = 127; 127 | repeated google.protobuf.FloatValue repeated_float_wrapper = 128; 128 | repeated google.protobuf.UInt64Value repeated_uint64_wrapper = 129; 129 | repeated google.protobuf.UInt32Value repeated_uint32_wrapper = 130; 130 | repeated google.protobuf.StringValue repeated_string_wrapper = 131; 131 | repeated google.protobuf.BoolValue repeated_bool_wrapper = 132; 132 | repeated google.protobuf.BytesValue repeated_bytes_wrapper = 133; 133 | repeated google.protobuf.ListValue repeated_list_value = 134; 134 | repeated google.protobuf.NullValue repeated_null_value = 135; 135 | 136 | // Map 137 | map map_int64_nested_type = 62; 138 | 139 | map map_bool_bool = 63; 140 | map map_bool_string = 64; 141 | map map_bool_bytes = 65; 142 | map map_bool_int32 = 66; 143 | map map_bool_int64 = 67; 144 | map map_bool_uint32 = 68; 145 | map map_bool_uint64 = 69; 146 | map map_bool_float = 70; 147 | map map_bool_double = 71; 148 | map map_bool_enum = 72; 149 | map map_bool_message = 73; 150 | map map_bool_duration = 228; 151 | map map_bool_timestamp = 229; 152 | map map_bool_null_value = 230; 153 | map map_bool_any = 246; 154 | map map_bool_struct = 247; 155 | map map_bool_value = 248; 156 | map map_bool_list_value = 249; 157 | map map_bool_int64_wrapper = 250; 158 | map map_bool_int32_wrapper = 251; 159 | map map_bool_double_wrapper = 252; 160 | map map_bool_float_wrapper = 253; 161 | map map_bool_uint64_wrapper = 254; 162 | map map_bool_uint32_wrapper = 255; 163 | map map_bool_string_wrapper = 256; 164 | map map_bool_bool_wrapper = 257; 165 | map map_bool_bytes_wrapper = 258; 166 | 167 | map map_int32_bool = 74; 168 | map map_int32_string = 75; 169 | map map_int32_bytes = 76; 170 | map map_int32_int32 = 77; 171 | map map_int32_int64 = 78; 172 | map map_int32_uint32 = 79; 173 | map map_int32_uint64 = 80; 174 | map map_int32_float = 81; 175 | map map_int32_double = 82; 176 | map map_int32_enum = 83; 177 | map map_int32_message = 84; 178 | map map_int32_duration = 231; 179 | map map_int32_timestamp = 232; 180 | map map_int32_null_value = 233; 181 | map map_int32_any = 259; 182 | map map_int32_struct = 260; 183 | map map_int32_value = 261; 184 | map map_int32_list_value = 262; 185 | map map_int32_int64_wrapper = 263; 186 | map map_int32_int32_wrapper = 264; 187 | map map_int32_double_wrapper = 265; 188 | map map_int32_float_wrapper = 266; 189 | map map_int32_uint64_wrapper = 267; 190 | map map_int32_uint32_wrapper = 268; 191 | map map_int32_string_wrapper = 269; 192 | map map_int32_bool_wrapper = 270; 193 | map map_int32_bytes_wrapper = 271; 194 | 195 | map map_int64_bool = 85; 196 | map map_int64_string = 86; 197 | map map_int64_bytes = 87; 198 | map map_int64_int32 = 88; 199 | map map_int64_int64 = 89; 200 | map map_int64_uint32 = 90; 201 | map map_int64_uint64 = 91; 202 | map map_int64_float = 92; 203 | map map_int64_double = 93; 204 | map map_int64_enum = 94; 205 | map map_int64_message = 95; 206 | map map_int64_duration = 234; 207 | map map_int64_timestamp = 235; 208 | map map_int64_null_value = 236; 209 | map map_int64_any = 272; 210 | map map_int64_struct = 273; 211 | map map_int64_value = 274; 212 | map map_int64_list_value = 275; 213 | map map_int64_int64_wrapper = 276; 214 | map map_int64_int32_wrapper = 277; 215 | map map_int64_double_wrapper = 278; 216 | map map_int64_float_wrapper = 279; 217 | map map_int64_uint64_wrapper = 280; 218 | map map_int64_uint32_wrapper = 281; 219 | map map_int64_string_wrapper = 282; 220 | map map_int64_bool_wrapper = 283; 221 | map map_int64_bytes_wrapper = 284; 222 | 223 | map map_uint32_bool = 96; 224 | map map_uint32_string = 97; 225 | map map_uint32_bytes = 98; 226 | map map_uint32_int32 = 99; 227 | map map_uint32_int64 = 200; 228 | map map_uint32_uint32 = 201; 229 | map map_uint32_uint64 = 202; 230 | map map_uint32_float = 203; 231 | map map_uint32_double = 204; 232 | map map_uint32_enum = 205; 233 | map map_uint32_message = 206; 234 | map map_uint32_duration = 237; 235 | map map_uint32_timestamp = 238; 236 | map map_uint32_null_value = 239; 237 | map map_uint32_any = 285; 238 | map map_uint32_struct = 286; 239 | map map_uint32_value = 287; 240 | map map_uint32_list_value = 288; 241 | map map_uint32_int64_wrapper = 289; 242 | map map_uint32_int32_wrapper = 290; 243 | map map_uint32_double_wrapper = 291; 244 | map map_uint32_float_wrapper = 292; 245 | map map_uint32_uint64_wrapper = 293; 246 | map map_uint32_uint32_wrapper = 294; 247 | map map_uint32_string_wrapper = 295; 248 | map map_uint32_bool_wrapper = 296; 249 | map map_uint32_bytes_wrapper = 297; 250 | 251 | map map_uint64_bool = 207; 252 | map map_uint64_string = 208; 253 | map map_uint64_bytes = 209; 254 | map map_uint64_int32 = 210; 255 | map map_uint64_int64 = 211; 256 | map map_uint64_uint32 = 212; 257 | map map_uint64_uint64 = 213; 258 | map map_uint64_float = 214; 259 | map map_uint64_double = 215; 260 | map map_uint64_enum = 216; 261 | map map_uint64_message = 217; 262 | map map_uint64_duration = 240; 263 | map map_uint64_timestamp = 241; 264 | map map_uint64_null_value = 242; 265 | map map_uint64_any = 298; 266 | map map_uint64_struct = 299; 267 | map map_uint64_value = 300; 268 | map map_uint64_list_value = 301; 269 | map map_uint64_int64_wrapper = 302; 270 | map map_uint64_int32_wrapper = 303; 271 | map map_uint64_double_wrapper = 304; 272 | map map_uint64_float_wrapper = 305; 273 | map map_uint64_uint64_wrapper = 306; 274 | map map_uint64_uint32_wrapper = 307; 275 | map map_uint64_string_wrapper = 308; 276 | map map_uint64_bool_wrapper = 309; 277 | map map_uint64_bytes_wrapper = 310; 278 | 279 | map map_string_bool = 218; 280 | map map_string_string = 61; 281 | map map_string_bytes = 219; 282 | map map_string_int32 = 220; 283 | map map_string_int64 = 221; 284 | map map_string_uint32 = 222; 285 | map map_string_uint64 = 223; 286 | map map_string_float = 224; 287 | map map_string_double = 225; 288 | map map_string_enum = 226; 289 | map map_string_message = 227; 290 | map map_string_duration = 243; 291 | map map_string_timestamp = 244; 292 | map map_string_null_value = 245; 293 | map map_string_any = 311; 294 | map map_string_struct = 312; 295 | map map_string_value = 313; 296 | map map_string_list_value = 314; 297 | map map_string_int64_wrapper = 315; 298 | map map_string_int32_wrapper = 316; 299 | map map_string_double_wrapper = 317; 300 | map map_string_float_wrapper = 318; 301 | map map_string_uint64_wrapper = 319; 302 | map map_string_uint32_wrapper = 320; 303 | map map_string_string_wrapper = 321; 304 | map map_string_bool_wrapper = 322; 305 | map map_string_bytes_wrapper = 323; 306 | } 307 | 308 | // This proto includes a recursively nested message. 309 | message NestedTestAllTypes { 310 | NestedTestAllTypes child = 1; 311 | TestAllTypes payload = 2; 312 | } 313 | 314 | // This proto tests that global enums are resolved correctly. 315 | enum GlobalEnum { 316 | GOO = 0; 317 | GAR = 1; 318 | GAZ = 2; 319 | } 320 | --------------------------------------------------------------------------------