pax_global_header00006660000000000000000000000064151565374040014524gustar00rootroot0000000000000052 comment=4708c8293763135821a59ba626743d3e89638c79 golang-github-mwitkow-go-proto-validators-0.3.2/000077500000000000000000000000001515653740400216665ustar00rootroot00000000000000golang-github-mwitkow-go-proto-validators-0.3.2/.bazelignore000066400000000000000000000000061515653740400241640ustar00rootroot00000000000000deps/ golang-github-mwitkow-go-proto-validators-0.3.2/.bazelrc000066400000000000000000000012211515653740400233050ustar00rootroot00000000000000build:download_all --build_runfile_links build:download_all --noexperimental_inmemory_jdeps_files build:download_all --noexperimental_inmemory_dotd_files build:download_all --experimental_remote_download_outputs=all build:disable_caches --config=download_all # This is necessary because toplevel is unsafe to set if there's no cache. build:disable_caches --remote_http_cache= build:disable_caches --remote_cache= build:disable_caches --repository_cache= build:disable_caches --disk_cache= build:disable_caches --remote_accept_cached=false build:disable_caches --config=disable_remote_upload build:disable_remote_upload --remote_upload_local_results=false golang-github-mwitkow-go-proto-validators-0.3.2/.gitignore000066400000000000000000000001521515653740400236540ustar00rootroot00000000000000# IDE configurations. *~ *.idea *.iml .idea_modules .vscode # Build and script artefacts. deps/ bazel-* golang-github-mwitkow-go-proto-validators-0.3.2/.travis.yml000066400000000000000000000006051515653740400240000ustar00rootroot00000000000000language: go env: global: - GO111MODULE=on - PROTOBUF_VERSION="3.8.0" notifications: email: false branches: only: - master jobs: include: - stage: test script: make test go: 1.11.x - script: make test go: 1.12.x - script: make test go: 1.13.x - script: make test go: 1.14.x - script: make test go: master golang-github-mwitkow-go-proto-validators-0.3.2/BUILD.bazel000066400000000000000000000044251515653740400235510ustar00rootroot00000000000000load("@bazel_gazelle//:def.bzl", "gazelle") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") gazelle( name = "gazelle", ) # gazelle:prefix github.com/mwitkow/go-proto-validators # gazelle:build_file_name BUILD.bazel # By default resolve the top-level package to the gogo variant as it's required for the plugin compilation. # gazelle:resolve go github.com/mwitkow/go-proto-validators //:validators_gogo go_proto_compiler( name = "go_proto_validators", options = ["gogoimport=false"], plugin = "//protoc-gen-govalidators", suffix = ".validator.pb.go", valid_archive = False, visibility = ["//visibility:public"], deps = [ ":validators_golang", ], ) go_proto_compiler( name = "gogo_proto_validators", options = ["gogoimport=true"], plugin = "//protoc-gen-govalidators", suffix = ".validator.pb.go", valid_archive = False, visibility = ["//visibility:public"], deps = [ ":validators_gogo", ], ) go_proto_library( name = "_validators_gogo", compilers = [ "@io_bazel_rules_go//proto:gogo_proto", ], importpath = "github.com/mwitkow/go-proto-validators", proto = ":validator_proto", visibility = ["//:__pkg__"], ) go_proto_library( name = "_validators_golang", compilers = [ "@io_bazel_rules_go//proto:go_proto", ], importpath = "github.com/mwitkow/go-proto-validators", proto = ":validator_proto", visibility = ["//:__pkg__"], ) go_library( name = "validators_gogo", srcs = ["helper.go"], embed = [":_validators_gogo"], importpath = "github.com/mwitkow/go-proto-validators", visibility = ["//visibility:public"], ) go_library( name = "validators_golang", srcs = ["helper.go"], embed = [":_validators_golang"], importpath = "github.com/mwitkow/go-proto-validators", visibility = ["//visibility:public"], ) proto_library( name = "validator_proto", srcs = ["validator.proto"], import_prefix = "github.com/mwitkow/go-proto-validators", visibility = ["//visibility:public"], deps = ["@com_google_protobuf//:descriptor_proto"], ) golang-github-mwitkow-go-proto-validators-0.3.2/LICENSE.txt000066400000000000000000000261141515653740400235150ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.golang-github-mwitkow-go-proto-validators-0.3.2/Makefile000066400000000000000000000040671515653740400233350ustar00rootroot00000000000000# Copyright 2016 Michal Witkowski. All Rights Reserved. # See LICENSE for licensing terms. mkfile_dir = "$(dir $(abspath $(lastword $(MAKEFILE_LIST))))" ifdef GOBIN extra_path = "$(mkfile_dir)deps/bin:$(GOBIN)" else extra_path = "$(mkfile_dir)deps/bin:$(HOME)/go/bin" endif prepare_deps: @echo "--- Preparing dependencies." @bash scripts/prepare-deps.sh gazelle: @bash bazel run --run_under="cd ${mkfile_dir} && " @bazel_gazelle//cmd/gazelle -- update-repos -from_file=go.mod -to_macro=go_deps.bzl%go_repositories @bash bazel run //:gazelle -- --mode=fix --exclude=deps --exclude=examples --exclude=test install: @echo "--- Installing 'govalidators' binary to GOBIN." go install github.com/mwitkow/go-proto-validators/protoc-gen-govalidators regenerate_test_gogo: prepare_deps install @echo "--- Regenerating test .proto files with gogo imports" export PATH=$(extra_path):$${PATH}; protoc \ --proto_path=deps \ --proto_path=deps/include \ --proto_path=test \ --gogo_out=test/gogo \ --govalidators_out=gogoimport=true:test/gogo test/*.proto regenerate_test_golang: prepare_deps install @echo "--- Regenerating test .proto files with golang imports" export PATH=$(extra_path):$${PATH}; protoc \ --proto_path=deps \ --proto_path=deps/include \ --proto_path=test \ --go_out=test/golang \ --govalidators_out=test/golang test/*.proto regenerate_example: prepare_deps install @echo "--- Regenerating example directory" export PATH=$(extra_path):$${PATH}; protoc \ --proto_path=deps \ --proto_path=deps/include \ --proto_path=. \ --go_out=. \ --govalidators_out=. examples/*.proto test: regenerate_test_gogo regenerate_test_golang @echo "Running tests" go test -v ./... regenerate: prepare_deps @echo "--- Regenerating validator.proto" export PATH=$(extra_path):$${PATH}; protoc \ --proto_path=deps \ --proto_path=deps/include \ --proto_path=deps/github.com/gogo/protobuf/protobuf \ --proto_path=. \ --gogo_out=Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor:. \ validator.proto clean: rm -rf "deps" golang-github-mwitkow-go-proto-validators-0.3.2/README.md000066400000000000000000000111521515653740400231450ustar00rootroot00000000000000# Golang ProtoBuf Validator Compiler [![Travis Build](https://travis-ci.org/mwitkow/go-proto-validators.svg)](https://travis-ci.org/mwitkow/go-proto-validators) [![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) A `protoc` plugin that generates `Validate() error` functions on Go proto `struct`s based on field options inside `.proto` files. The validation functions are code-generated and thus don't suffer on performance from tag-based reflection on deeply-nested messages. ## Requirements Using Protobuf validators is currently verified to work with: - Go 1.11, 1.12, 1.13 - [Protobuf](https://github.com/protocolbuffers/protobuf) @ `v3.8.0` - [Go Protobuf](https://github.com/golang/protobuf) @ `v1.3.2` - [Gogo Protobuf](https://github.com/gogo/protobuf) @ `v1.3.0` It _should_ still be possible to use it in project using earlier Go versions. However if you want to contribute to this repository you'll need at least 1.11 for Go module support. ## Paint me a code picture Let's take the following `proto3` snippet: ```proto syntax = "proto3"; package validator.examples; import "github.com/mwitkow/go-proto-validators/validator.proto"; message InnerMessage { // some_integer can only be in range (0, 100). int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}]; // some_float can only be in range (0;1). double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}]; } message OuterMessage { // important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax). string important_string = 1 [(validator.field) = {regex: "^[a-z0-9]{5,30}$"}]; // proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage. InnerMessage inner = 2 [(validator.field) = {msg_exists : true}]; } ``` First, the **`required` keyword is back** for `proto3`, under the guise of `msg_exists`. The painful `if-nil` checks are taken care of! Second, the expected values in fields are now part of the contract `.proto` file. No more hunting down conditions in code! Third, the generated code is understandable and has clear understandable error messages. Take a look: ```go func (this *InnerMessage) Validate() error { if !(this.SomeInteger > 0) { return fmt.Errorf("validation error: InnerMessage.SomeInteger must be greater than '0'") } if !(this.SomeInteger < 100) { return fmt.Errorf("validation error: InnerMessage.SomeInteger must be less than '100'") } if !(this.SomeFloat >= 0) { return fmt.Errorf("validation error: InnerMessage.SomeFloat must be greater than or equal to '0'") } if !(this.SomeFloat <= 1) { return fmt.Errorf("validation error: InnerMessage.SomeFloat must be less than or equal to '1'") } return nil } var _regex_OuterMessage_ImportantString = regexp.MustCompile("^[a-z0-9]{5,30}$") func (this *OuterMessage) Validate() error { if !_regex_OuterMessage_ImportantString.MatchString(this.ImportantString) { return fmt.Errorf("validation error: OuterMessage.ImportantString must conform to regex '^[a-z0-9]{5,30}$'") } if nil == this.Inner { return fmt.Errorf("validation error: OuterMessage.Inner message must exist") } if this.Inner != nil { if err := validators.CallValidatorIfExists(this.Inner); err != nil { return err } } return nil } ``` ## Installing and using The `protoc` compiler expects to find plugins named `proto-gen-XYZ` on the execution `$PATH`. So first: ```sh export PATH=${PATH}:${GOPATH}/bin ``` Then, do the usual ```sh go get github.com/mwitkow/go-proto-validators/protoc-gen-govalidators ``` Your `protoc` builds probably look very simple like: ```sh protoc \ --proto_path=. \ --go_out=. \ *.proto ``` That's fine, until you encounter `.proto` includes. Because `go-proto-validators` uses field options inside the `.proto` files themselves, it's `.proto` definition (and the Google `descriptor.proto` itself) need to on the `protoc` include path. Hence the above becomes: ```sh protoc \ --proto_path=${GOPATH}/src \ --proto_path=${GOPATH}/src/github.com/google/protobuf/src \ --proto_path=. \ --go_out=. \ --govalidators_out=. \ *.proto ``` Or with gogo protobufs: ```sh protoc \ --proto_path=${GOPATH}/src \ --proto_path=${GOPATH}/src/github.com/gogo/protobuf/protobuf \ --proto_path=. \ --gogo_out=. \ --govalidators_out=gogoimport=true:. \ *.proto ``` Basically the magical incantation (apart from includes) is the `--govalidators_out`. That triggers the `protoc-gen-govalidators` plugin to generate `mymessage.validator.pb.go`. That's it :) ## License `go-proto-validators` is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details. golang-github-mwitkow-go-proto-validators-0.3.2/WORKSPACE000066400000000000000000000037701515653740400231560ustar00rootroot00000000000000workspace(name = "com_github_mwitkow_go_proto_validators") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") GO_VERSION = "1.14.7" http_archive( name = "bazel_skylib", sha256 = "64ad2728ccdd2044216e4cec7815918b7bb3bb28c95b7e9d951f9d4eccb07625", strip_prefix = "bazel-skylib-1.0.2", url = "https://github.com/bazelbuild/bazel-skylib/archive/1.0.2.zip", ) load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() http_archive( name = "rules_proto", sha256 = "296ffd3e7992bd83fa75151255f7c7f27d22d6e52e2fd3c3d3d10c292317fbed", strip_prefix = "rules_proto-f6c112fa4eb2b8f934feb938a6fce41425e41587", urls = [ "https://github.com/bazelbuild/rules_proto/archive/f6c112fa4eb2b8f934feb938a6fce41425e41587.tar.gz", ], ) http_archive( name = "com_google_protobuf", sha256 = "e5265d552e12c1f39c72842fa91d84941726026fa056d914ea6a25cd58d7bbf8", strip_prefix = "protobuf-3.12.3", url = "https://github.com/protocolbuffers/protobuf/archive/v3.12.3.zip", ) load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") protobuf_deps() http_archive( name = "io_bazel_rules_go", sha256 = "0310e837aed522875791750de44408ec91046c630374990edd51827cb169f616", urls = [ "https://github.com/bazelbuild/rules_go/releases/download/v0.23.7/rules_go-v0.23.7.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") go_rules_dependencies() go_register_toolchains(go_version = GO_VERSION) http_archive( name = "bazel_gazelle", sha256 = "2423201f91471ea87925b81962258e27a22cd8ebb4fe355bf033dcf2ad668541", strip_prefix = "bazel-gazelle-0.21.1", urls = [ "https://github.com/bazelbuild/bazel-gazelle/archive/v0.21.1.tar.gz", ], ) load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") gazelle_dependencies() load("go_deps.bzl", "go_repositories") go_repositories() # gazelle:repository_macro go_deps.bzl%go_repositories golang-github-mwitkow-go-proto-validators-0.3.2/examples/000077500000000000000000000000001515653740400235045ustar00rootroot00000000000000golang-github-mwitkow-go-proto-validators-0.3.2/examples/.gitignore000066400000000000000000000000101515653740400254630ustar00rootroot00000000000000!*.pb.gogolang-github-mwitkow-go-proto-validators-0.3.2/examples/enum.pb.go000066400000000000000000000072631515653740400254070ustar00rootroot00000000000000// Code generated by protoc-gen-go. DO NOT EDIT. // source: examples/enum.proto package validator_examples import ( fmt "fmt" proto "github.com/golang/protobuf/proto" _ "github.com/mwitkow/go-proto-validators" math "math" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package type Action int32 const ( Action_ALLOW Action = 0 Action_DENY Action = 1 Action_CHILL Action = 2 ) var Action_name = map[int32]string{ 0: "ALLOW", 1: "DENY", 2: "CHILL", } var Action_value = map[string]int32{ "ALLOW": 0, "DENY": 1, "CHILL": 2, } func (x Action) String() string { return proto.EnumName(Action_name, int32(x)) } func (Action) EnumDescriptor() ([]byte, []int) { return fileDescriptor_5e21dd5d0da6895c, []int{0} } type SomeMsg struct { Do Action `protobuf:"varint,1,opt,name=do,proto3,enum=validator.examples.Action" json:"do,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *SomeMsg) Reset() { *m = SomeMsg{} } func (m *SomeMsg) String() string { return proto.CompactTextString(m) } func (*SomeMsg) ProtoMessage() {} func (*SomeMsg) Descriptor() ([]byte, []int) { return fileDescriptor_5e21dd5d0da6895c, []int{0} } func (m *SomeMsg) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SomeMsg.Unmarshal(m, b) } func (m *SomeMsg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SomeMsg.Marshal(b, m, deterministic) } func (m *SomeMsg) XXX_Merge(src proto.Message) { xxx_messageInfo_SomeMsg.Merge(m, src) } func (m *SomeMsg) XXX_Size() int { return xxx_messageInfo_SomeMsg.Size(m) } func (m *SomeMsg) XXX_DiscardUnknown() { xxx_messageInfo_SomeMsg.DiscardUnknown(m) } var xxx_messageInfo_SomeMsg proto.InternalMessageInfo func (m *SomeMsg) GetDo() Action { if m != nil { return m.Do } return Action_ALLOW } func init() { proto.RegisterEnum("validator.examples.Action", Action_name, Action_value) proto.RegisterType((*SomeMsg)(nil), "validator.examples.SomeMsg") } func init() { proto.RegisterFile("examples/enum.proto", fileDescriptor_5e21dd5d0da6895c) } var fileDescriptor_5e21dd5d0da6895c = []byte{ // 183 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0xad, 0x48, 0xcc, 0x2d, 0xc8, 0x49, 0x2d, 0xd6, 0x4f, 0xcd, 0x2b, 0xcd, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x2a, 0x4b, 0xcc, 0xc9, 0x4c, 0x49, 0x2c, 0xc9, 0x2f, 0xd2, 0x83, 0x49, 0x4b, 0x99, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xe7, 0x96, 0x67, 0x96, 0x64, 0xe7, 0x97, 0xeb, 0xa7, 0xe7, 0xeb, 0x82, 0x35, 0xe8, 0xc2, 0xd5, 0x17, 0xeb, 0x23, 0xb4, 0x82, 0xa5, 0x94, 0xec, 0xb8, 0xd8, 0x83, 0xf3, 0x73, 0x53, 0x7d, 0x8b, 0xd3, 0x85, 0x8c, 0xb9, 0x98, 0x52, 0xf2, 0x25, 0x18, 0x15, 0x18, 0x35, 0xf8, 0x8c, 0xa4, 0xf4, 0x30, 0xed, 0xd0, 0x73, 0x4c, 0x2e, 0xc9, 0xcc, 0xcf, 0x73, 0x62, 0x7f, 0x74, 0x5f, 0x9e, 0xb9, 0x83, 0x91, 0x31, 0x88, 0x29, 0x25, 0x5f, 0x4b, 0x83, 0x8b, 0x0d, 0x22, 0x2c, 0xc4, 0xc9, 0xc5, 0xea, 0xe8, 0xe3, 0xe3, 0x1f, 0x2e, 0xc0, 0x20, 0xc4, 0xc1, 0xc5, 0xe2, 0xe2, 0xea, 0x17, 0x29, 0xc0, 0x08, 0x12, 0x74, 0xf6, 0xf0, 0xf4, 0xf1, 0x11, 0x60, 0x4a, 0x62, 0x03, 0x5b, 0x68, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x8d, 0x4f, 0x55, 0x68, 0xd3, 0x00, 0x00, 0x00, } golang-github-mwitkow-go-proto-validators-0.3.2/examples/enum.proto000066400000000000000000000003671515653740400255430ustar00rootroot00000000000000syntax = "proto3"; package validator.examples; import "github.com/mwitkow/go-proto-validators/validator.proto"; message SomeMsg { Action do = 1 [(validator.field) = {is_in_enum : true}]; } enum Action { ALLOW = 0; DENY = 1; CHILL = 2; } golang-github-mwitkow-go-proto-validators-0.3.2/examples/enum.validator.pb.go000066400000000000000000000012471515653740400273670ustar00rootroot00000000000000// Code generated by protoc-gen-gogo. DO NOT EDIT. // source: examples/enum.proto package validator_examples import ( fmt "fmt" math "math" proto "github.com/golang/protobuf/proto" _ "github.com/mwitkow/go-proto-validators" github_com_mwitkow_go_proto_validators "github.com/mwitkow/go-proto-validators" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf func (this *SomeMsg) Validate() error { if _, ok := Action_name[int32(this.Do)]; !ok { return github_com_mwitkow_go_proto_validators.FieldError("Do", fmt.Errorf(`value '%v' must be a valid Action field`, this.Do)) } return nil } golang-github-mwitkow-go-proto-validators-0.3.2/examples/nested.pb.go000066400000000000000000000127021515653740400257170ustar00rootroot00000000000000// Code generated by protoc-gen-go. DO NOT EDIT. // source: examples/nested.proto package validator_examples import ( fmt "fmt" proto "github.com/golang/protobuf/proto" _ "github.com/mwitkow/go-proto-validators" math "math" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package type InnerMessage struct { // some_integer can only be in range (1, 100). SomeInteger int32 `protobuf:"varint,1,opt,name=some_integer,json=someInteger,proto3" json:"some_integer,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *InnerMessage) Reset() { *m = InnerMessage{} } func (m *InnerMessage) String() string { return proto.CompactTextString(m) } func (*InnerMessage) ProtoMessage() {} func (*InnerMessage) Descriptor() ([]byte, []int) { return fileDescriptor_48ff2d59662eadb1, []int{0} } func (m *InnerMessage) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InnerMessage.Unmarshal(m, b) } func (m *InnerMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_InnerMessage.Marshal(b, m, deterministic) } func (m *InnerMessage) XXX_Merge(src proto.Message) { xxx_messageInfo_InnerMessage.Merge(m, src) } func (m *InnerMessage) XXX_Size() int { return xxx_messageInfo_InnerMessage.Size(m) } func (m *InnerMessage) XXX_DiscardUnknown() { xxx_messageInfo_InnerMessage.DiscardUnknown(m) } var xxx_messageInfo_InnerMessage proto.InternalMessageInfo func (m *InnerMessage) GetSomeInteger() int32 { if m != nil { return m.SomeInteger } return 0 } type OuterMessage struct { // important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax). ImportantString string `protobuf:"bytes,1,opt,name=important_string,json=importantString,proto3" json:"important_string,omitempty"` // proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage. Inner *InnerMessage `protobuf:"bytes,2,opt,name=inner,proto3" json:"inner,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *OuterMessage) Reset() { *m = OuterMessage{} } func (m *OuterMessage) String() string { return proto.CompactTextString(m) } func (*OuterMessage) ProtoMessage() {} func (*OuterMessage) Descriptor() ([]byte, []int) { return fileDescriptor_48ff2d59662eadb1, []int{1} } func (m *OuterMessage) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OuterMessage.Unmarshal(m, b) } func (m *OuterMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OuterMessage.Marshal(b, m, deterministic) } func (m *OuterMessage) XXX_Merge(src proto.Message) { xxx_messageInfo_OuterMessage.Merge(m, src) } func (m *OuterMessage) XXX_Size() int { return xxx_messageInfo_OuterMessage.Size(m) } func (m *OuterMessage) XXX_DiscardUnknown() { xxx_messageInfo_OuterMessage.DiscardUnknown(m) } var xxx_messageInfo_OuterMessage proto.InternalMessageInfo func (m *OuterMessage) GetImportantString() string { if m != nil { return m.ImportantString } return "" } func (m *OuterMessage) GetInner() *InnerMessage { if m != nil { return m.Inner } return nil } func init() { proto.RegisterType((*InnerMessage)(nil), "validator.examples.InnerMessage") proto.RegisterType((*OuterMessage)(nil), "validator.examples.OuterMessage") } func init() { proto.RegisterFile("examples/nested.proto", fileDescriptor_48ff2d59662eadb1) } var fileDescriptor_48ff2d59662eadb1 = []byte{ // 249 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4d, 0xad, 0x48, 0xcc, 0x2d, 0xc8, 0x49, 0x2d, 0xd6, 0xcf, 0x4b, 0x2d, 0x2e, 0x49, 0x4d, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x2a, 0x4b, 0xcc, 0xc9, 0x4c, 0x49, 0x2c, 0xc9, 0x2f, 0xd2, 0x83, 0x29, 0x90, 0x32, 0x4b, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0xcf, 0x2d, 0xcf, 0x2c, 0xc9, 0xce, 0x2f, 0xd7, 0x4f, 0xcf, 0xd7, 0x05, 0x6b, 0xd0, 0x85, 0xab, 0x2f, 0xd6, 0x47, 0x68, 0x05, 0x4b, 0x29, 0x59, 0x73, 0xf1, 0x78, 0xe6, 0xe5, 0xa5, 0x16, 0xf9, 0xa6, 0x16, 0x17, 0x27, 0xa6, 0xa7, 0x0a, 0x69, 0x73, 0xf1, 0x14, 0xe7, 0xe7, 0xa6, 0xc6, 0x67, 0xe6, 0x95, 0xa4, 0xa6, 0xa7, 0x16, 0x49, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x3a, 0x71, 0x3c, 0xba, 0x2f, 0xcf, 0x22, 0xc0, 0x20, 0x91, 0x12, 0xc4, 0x0d, 0x92, 0xf5, 0x84, 0x48, 0x2a, 0xf5, 0x32, 0x72, 0xf1, 0xf8, 0x97, 0x96, 0x20, 0x74, 0xdb, 0x72, 0x09, 0x64, 0xe6, 0x16, 0xe4, 0x17, 0x95, 0x24, 0xe6, 0x95, 0xc4, 0x17, 0x97, 0x14, 0x65, 0xe6, 0xa5, 0x83, 0x4d, 0xe0, 0x74, 0x12, 0x7a, 0x74, 0x5f, 0x9e, 0x8f, 0x8b, 0x27, 0x2e, 0x3a, 0x51, 0xb7, 0x2a, 0xb6, 0xda, 0x48, 0xc7, 0xb4, 0x56, 0x25, 0x88, 0x1f, 0xae, 0x36, 0x18, 0xac, 0x54, 0xc8, 0x8e, 0x8b, 0x35, 0x13, 0xe4, 0x18, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x05, 0x3d, 0x4c, 0x8f, 0xea, 0x21, 0xbb, 0xd6, 0x89, 0xed, 0xd1, 0x7d, 0x79, 0x26, 0x05, 0xc6, 0x20, 0x88, 0xb6, 0x24, 0x36, 0xb0, 0x9f, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x08, 0x68, 0xd9, 0xd5, 0x38, 0x01, 0x00, 0x00, } golang-github-mwitkow-go-proto-validators-0.3.2/examples/nested.proto000066400000000000000000000011431515653740400260520ustar00rootroot00000000000000syntax = "proto3"; package validator.examples; import "github.com/mwitkow/go-proto-validators/validator.proto"; message InnerMessage { // some_integer can only be in range (1, 100). int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}]; } message OuterMessage { // important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax). string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}]; // proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage. InnerMessage inner = 2 [(validator.field) = {msg_exists : true}]; } golang-github-mwitkow-go-proto-validators-0.3.2/examples/nested.validator.pb.go000066400000000000000000000031051515653740400277000ustar00rootroot00000000000000// Code generated by protoc-gen-gogo. DO NOT EDIT. // source: examples/nested.proto package validator_examples import ( fmt "fmt" math "math" proto "github.com/golang/protobuf/proto" _ "github.com/mwitkow/go-proto-validators" regexp "regexp" github_com_mwitkow_go_proto_validators "github.com/mwitkow/go-proto-validators" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf func (this *InnerMessage) Validate() error { if !(this.SomeInteger > 0) { return github_com_mwitkow_go_proto_validators.FieldError("SomeInteger", fmt.Errorf(`value '%v' must be greater than '0'`, this.SomeInteger)) } if !(this.SomeInteger < 100) { return github_com_mwitkow_go_proto_validators.FieldError("SomeInteger", fmt.Errorf(`value '%v' must be less than '100'`, this.SomeInteger)) } return nil } var _regex_OuterMessage_ImportantString = regexp.MustCompile(`^[a-z]{2,5}$`) func (this *OuterMessage) Validate() error { if !_regex_OuterMessage_ImportantString.MatchString(this.ImportantString) { return github_com_mwitkow_go_proto_validators.FieldError("ImportantString", fmt.Errorf(`value '%v' must be a string conforming to regex "^[a-z]{2,5}$"`, this.ImportantString)) } if nil == this.Inner { return github_com_mwitkow_go_proto_validators.FieldError("Inner", fmt.Errorf("message must exist")) } if this.Inner != nil { if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Inner); err != nil { return github_com_mwitkow_go_proto_validators.FieldError("Inner", err) } } return nil } golang-github-mwitkow-go-proto-validators-0.3.2/examples/uuid.pb.go000066400000000000000000000057341515653740400254120ustar00rootroot00000000000000// Code generated by protoc-gen-go. DO NOT EDIT. // source: examples/uuid.proto package validator_examples import ( fmt "fmt" proto "github.com/golang/protobuf/proto" _ "github.com/mwitkow/go-proto-validators" math "math" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package type UUIDMsg struct { // user_id must be a valid version 4 UUID. UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *UUIDMsg) Reset() { *m = UUIDMsg{} } func (m *UUIDMsg) String() string { return proto.CompactTextString(m) } func (*UUIDMsg) ProtoMessage() {} func (*UUIDMsg) Descriptor() ([]byte, []int) { return fileDescriptor_0029f00507e892b3, []int{0} } func (m *UUIDMsg) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UUIDMsg.Unmarshal(m, b) } func (m *UUIDMsg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_UUIDMsg.Marshal(b, m, deterministic) } func (m *UUIDMsg) XXX_Merge(src proto.Message) { xxx_messageInfo_UUIDMsg.Merge(m, src) } func (m *UUIDMsg) XXX_Size() int { return xxx_messageInfo_UUIDMsg.Size(m) } func (m *UUIDMsg) XXX_DiscardUnknown() { xxx_messageInfo_UUIDMsg.DiscardUnknown(m) } var xxx_messageInfo_UUIDMsg proto.InternalMessageInfo func (m *UUIDMsg) GetUserId() string { if m != nil { return m.UserId } return "" } func init() { proto.RegisterType((*UUIDMsg)(nil), "validator.examples.UUIDMsg") } func init() { proto.RegisterFile("examples/uuid.proto", fileDescriptor_0029f00507e892b3) } var fileDescriptor_0029f00507e892b3 = []byte{ // 144 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0xad, 0x48, 0xcc, 0x2d, 0xc8, 0x49, 0x2d, 0xd6, 0x2f, 0x2d, 0xcd, 0x4c, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x2a, 0x4b, 0xcc, 0xc9, 0x4c, 0x49, 0x2c, 0xc9, 0x2f, 0xd2, 0x83, 0x49, 0x4b, 0x99, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0xe7, 0x96, 0x67, 0x96, 0x64, 0xe7, 0x97, 0xeb, 0xa7, 0xe7, 0xeb, 0x82, 0x35, 0xe8, 0xc2, 0xd5, 0x17, 0xeb, 0x23, 0xb4, 0x82, 0xa5, 0x94, 0x74, 0xb9, 0xd8, 0x43, 0x43, 0x3d, 0x5d, 0x7c, 0x8b, 0xd3, 0x85, 0x94, 0xb8, 0xd8, 0x4b, 0x8b, 0x53, 0x8b, 0xe2, 0x33, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x38, 0x9d, 0x38, 0x1f, 0xdd, 0x97, 0x67, 0x8d, 0x60, 0x9c, 0xc0, 0xc8, 0x12, 0xc4, 0x06, 0x92, 0xf1, 0x4c, 0x49, 0x62, 0x03, 0xeb, 0x32, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x56, 0xba, 0x22, 0x98, 0x00, 0x00, 0x00, } golang-github-mwitkow-go-proto-validators-0.3.2/examples/uuid.proto000066400000000000000000000004041515653740400255350ustar00rootroot00000000000000syntax = "proto3"; package validator.examples; import "github.com/mwitkow/go-proto-validators/validator.proto"; message UUIDMsg { // user_id must be a valid version 4 UUID. string user_id = 1 [(validator.field) = {uuid_ver: 4, string_not_empty: true}]; } golang-github-mwitkow-go-proto-validators-0.3.2/examples/uuid.validator.pb.go000066400000000000000000000021441515653740400273660ustar00rootroot00000000000000// Code generated by protoc-gen-gogo. DO NOT EDIT. // source: examples/uuid.proto package validator_examples import ( fmt "fmt" math "math" proto "github.com/golang/protobuf/proto" _ "github.com/mwitkow/go-proto-validators" regexp "regexp" github_com_mwitkow_go_proto_validators "github.com/mwitkow/go-proto-validators" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf var _regex_UUIDMsg_UserId = regexp.MustCompile(`^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[4][a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12})?$`) func (this *UUIDMsg) Validate() error { if !_regex_UUIDMsg_UserId.MatchString(this.UserId) { return github_com_mwitkow_go_proto_validators.FieldError("UserId", fmt.Errorf(`value '%v' must be a string conforming to regex "^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[4][a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12})?$"`, this.UserId)) } if this.UserId == "" { return github_com_mwitkow_go_proto_validators.FieldError("UserId", fmt.Errorf(`value '%v' must not be an empty string`, this.UserId)) } return nil } golang-github-mwitkow-go-proto-validators-0.3.2/go.mod000066400000000000000000000002541515653740400227750ustar00rootroot00000000000000module github.com/mwitkow/go-proto-validators go 1.13 require ( github.com/gogo/protobuf v1.3.0 github.com/golang/protobuf v1.3.2 github.com/stretchr/testify v1.3.0 ) golang-github-mwitkow-go-proto-validators-0.3.2/go.sum000066400000000000000000000023211515653740400230170ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang-github-mwitkow-go-proto-validators-0.3.2/go_deps.bzl000066400000000000000000000037351515653740400240270ustar00rootroot00000000000000load("@bazel_gazelle//:deps.bzl", "go_repository") def go_repositories(): go_repository( name = "com_github_davecgh_go_spew", importpath = "github.com/davecgh/go-spew", sum = "h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=", version = "v1.1.0", ) go_repository( name = "com_github_gogo_protobuf", importpath = "github.com/gogo/protobuf", sum = "h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=", version = "v1.3.0", ) go_repository( name = "com_github_golang_protobuf", importpath = "github.com/golang/protobuf", sum = "h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=", version = "v1.3.2", ) go_repository( name = "com_github_kisielk_errcheck", importpath = "github.com/kisielk/errcheck", sum = "h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+E=", version = "v1.2.0", ) go_repository( name = "com_github_kisielk_gotool", importpath = "github.com/kisielk/gotool", sum = "h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=", version = "v1.0.0", ) go_repository( name = "com_github_pmezard_go_difflib", importpath = "github.com/pmezard/go-difflib", sum = "h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=", version = "v1.0.0", ) go_repository( name = "com_github_stretchr_objx", importpath = "github.com/stretchr/objx", sum = "h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=", version = "v0.1.0", ) go_repository( name = "com_github_stretchr_testify", importpath = "github.com/stretchr/testify", sum = "h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=", version = "v1.3.0", ) go_repository( name = "org_golang_x_tools", importpath = "golang.org/x/tools", sum = "h1:NIou6eNFigscvKJmsbyez16S2cIS6idossORlFtSt2E=", version = "v0.0.0-20181030221726-6c7e314b6563", ) golang-github-mwitkow-go-proto-validators-0.3.2/helper.go000066400000000000000000000016521515653740400235000ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. package validator import "strings" // Validator is a general interface that allows a message to be validated. type Validator interface { Validate() error } func CallValidatorIfExists(candidate interface{}) error { if validator, ok := candidate.(Validator); ok { return validator.Validate() } return nil } type fieldError struct { fieldStack []string nestedErr error } func (f *fieldError) Error() string { return "invalid field " + strings.Join(f.fieldStack, ".") + ": " + f.nestedErr.Error() } // FieldError wraps a given Validator error providing a message call stack. func FieldError(fieldName string, err error) error { if fErr, ok := err.(*fieldError); ok { fErr.fieldStack = append([]string{fieldName}, fErr.fieldStack...) return err } return &fieldError{ fieldStack: []string{fieldName}, nestedErr: err, } } golang-github-mwitkow-go-proto-validators-0.3.2/plugin/000077500000000000000000000000001515653740400231645ustar00rootroot00000000000000golang-github-mwitkow-go-proto-validators-0.3.2/plugin/BUILD.bazel000066400000000000000000000012061515653740400250410ustar00rootroot00000000000000load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", srcs = ["plugin.go"], importpath = "github.com/mwitkow/go-proto-validators/plugin", visibility = ["//visibility:public"], deps = [ "//:validators_gogo", "@com_github_gogo_protobuf//gogoproto:go_default_library", "@com_github_gogo_protobuf//proto:go_default_library", "@com_github_gogo_protobuf//protoc-gen-gogo/descriptor:go_default_library", "@com_github_gogo_protobuf//protoc-gen-gogo/generator:go_default_library", "@com_github_gogo_protobuf//vanity:go_default_library", ], ) golang-github-mwitkow-go-proto-validators-0.3.2/plugin/plugin.go000066400000000000000000000564171515653740400250260ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. /* The validator plugin generates a Validate method for each message. By default, if none of the message's fields are annotated with the gogo validator annotation, it returns a nil. In case some of the fields are annotated, the Validate function returns nil upon sucessful validation, or an error describing why the validation failed. The Validate method is called recursively for all submessage of the message. TODO(michal): ADD COMMENTS. Equal is enabled using the following extensions: - equal - equal_all While VerboseEqual is enable dusing the following extensions: - verbose_equal - verbose_equal_all The equal plugin also generates a test given it is enabled using one of the following extensions: - testgen - testgen_all Let us look at: github.com/gogo/protobuf/test/example/example.proto Btw all the output can be seen at: github.com/gogo/protobuf/test/example/* The following message: given to the equal plugin, will generate the following code: and the following test code: */ package plugin import ( "fmt" "os" "reflect" "strconv" "strings" "github.com/gogo/protobuf/gogoproto" "github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" "github.com/gogo/protobuf/protoc-gen-gogo/generator" "github.com/gogo/protobuf/vanity" validator "github.com/mwitkow/go-proto-validators" ) const uuidPattern = "^([a-fA-F0-9]{8}-" + "[a-fA-F0-9]{4}-" + "[%s][a-fA-F0-9]{3}-" + "[8|9|aA|bB][a-fA-F0-9]{3}-" + "[a-fA-F0-9]{12})?$" type plugin struct { *generator.Generator generator.PluginImports regexPkg generator.Single fmtPkg generator.Single validatorPkg generator.Single useGogoImport bool } func NewPlugin(useGogoImport bool) generator.Plugin { return &plugin{useGogoImport: useGogoImport} } func (p *plugin) Name() string { return "validator" } func (p *plugin) Init(g *generator.Generator) { p.Generator = g } func (p *plugin) Generate(file *generator.FileDescriptor) { if !p.useGogoImport { vanity.TurnOffGogoImport(file.FileDescriptorProto) } p.PluginImports = generator.NewPluginImports(p.Generator) p.regexPkg = p.NewImport("regexp") p.fmtPkg = p.NewImport("fmt") p.validatorPkg = p.NewImport("github.com/mwitkow/go-proto-validators") for _, msg := range file.Messages() { if msg.DescriptorProto.GetOptions().GetMapEntry() { continue } p.generateRegexVars(file, msg) if gogoproto.IsProto3(file.FileDescriptorProto) { p.generateProto3Message(file, msg) } else { p.generateProto2Message(file, msg) } } } func getFieldValidatorIfAny(field *descriptor.FieldDescriptorProto) *validator.FieldValidator { if field.Options != nil { v, err := proto.GetExtension(field.Options, validator.E_Field) if err == nil && v.(*validator.FieldValidator) != nil { return (v.(*validator.FieldValidator)) } } return nil } func getOneofValidatorIfAny(oneof *descriptor.OneofDescriptorProto) *validator.OneofValidator { if oneof.Options != nil { v, err := proto.GetExtension(oneof.Options, validator.E_Oneof) if err == nil && v.(*validator.OneofValidator) != nil { return (v.(*validator.OneofValidator)) } } return nil } func (p *plugin) isSupportedInt(field *descriptor.FieldDescriptorProto) bool { switch *(field.Type) { case descriptor.FieldDescriptorProto_TYPE_INT32, descriptor.FieldDescriptorProto_TYPE_INT64: return true case descriptor.FieldDescriptorProto_TYPE_UINT32, descriptor.FieldDescriptorProto_TYPE_UINT64: return true case descriptor.FieldDescriptorProto_TYPE_SINT32, descriptor.FieldDescriptorProto_TYPE_SINT64: return true } return false } func (p *plugin) isSupportedFloat(field *descriptor.FieldDescriptorProto) bool { switch *(field.Type) { case descriptor.FieldDescriptorProto_TYPE_FLOAT, descriptor.FieldDescriptorProto_TYPE_DOUBLE: return true case descriptor.FieldDescriptorProto_TYPE_FIXED32, descriptor.FieldDescriptorProto_TYPE_FIXED64: return true case descriptor.FieldDescriptorProto_TYPE_SFIXED32, descriptor.FieldDescriptorProto_TYPE_SFIXED64: return true } return false } func (p *plugin) generateRegexVars(file *generator.FileDescriptor, message *generator.Descriptor) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) for _, field := range message.Field { validator := getFieldValidatorIfAny(field) if validator != nil { fieldName := p.GetOneOfFieldName(message, field) if validator.Regex != nil && validator.UuidVer != nil { fmt.Fprintf(os.Stderr, "WARNING: regex and uuid validator is set for field %v.%v, only one of them can be set. Regex and UUID validator is ignored for this field.", ccTypeName, fieldName) } else if validator.UuidVer != nil { uuid, err := getUUIDRegex(validator.UuidVer) if err != nil { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v error %s.\n", ccTypeName, fieldName, err) } else { validator.Regex = &uuid p.P(`var `, p.regexName(ccTypeName, fieldName), ` = `, p.regexPkg.Use(), `.MustCompile(`, "`", *validator.Regex, "`", `)`) } } else if validator.Regex != nil { p.P(`var `, p.regexName(ccTypeName, fieldName), ` = `, p.regexPkg.Use(), `.MustCompile(`, "`", *validator.Regex, "`", `)`) } } } } func (p *plugin) GetFieldName(message *generator.Descriptor, field *descriptor.FieldDescriptorProto) string { fieldName := p.Generator.GetFieldName(message, field) if p.useGogoImport { return fieldName } if gogoproto.IsEmbed(field) { fieldName = generator.CamelCase(*field.Name) } return fieldName } func (p *plugin) GetOneOfFieldName(message *generator.Descriptor, field *descriptor.FieldDescriptorProto) string { fieldName := p.Generator.GetOneOfFieldName(message, field) if p.useGogoImport { return fieldName } if gogoproto.IsEmbed(field) { fieldName = generator.CamelCase(*field.Name) } return fieldName } func (p *plugin) generateProto2Message(file *generator.FileDescriptor, message *generator.Descriptor) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) p.P(`func (this *`, ccTypeName, `) Validate() error {`) p.In() for _, field := range message.Field { fieldName := p.GetFieldName(message, field) fieldValidator := getFieldValidatorIfAny(field) if fieldValidator == nil && !field.IsMessage() { continue } if p.validatorWithMessageExists(fieldValidator) { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is a proto2 message, validator.msg_exists has no effect\n", ccTypeName, fieldName) } variableName := "this." + fieldName repeated := field.IsRepeated() nullable := gogoproto.IsNullable(field) && !(p.useGogoImport && gogoproto.IsEmbed(field)) // For proto2 syntax, only Gogo generates non-pointer fields nonpointer := gogoproto.ImportsGoGoProto(file.FileDescriptorProto) && !gogoproto.IsNullable(field) if repeated { p.generateRepeatedCountValidator(variableName, ccTypeName, fieldName, fieldValidator) if field.IsMessage() || p.validatorWithNonRepeatedConstraint(fieldValidator) { p.P(`for _, item := range `, variableName, `{`) p.In() variableName = "item" } } else if nullable { p.P(`if `, variableName, ` != nil {`) p.In() if !field.IsBytes() { variableName = "*(" + variableName + ")" } } else if nonpointer { // can use the field directly } else if !field.IsMessage() { variableName = `this.Get` + fieldName + `()` } if !repeated && fieldValidator != nil { if fieldValidator.RepeatedCountMin != nil { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is not repeated, validator.min_elts has no effects\n", ccTypeName, fieldName) } if fieldValidator.RepeatedCountMax != nil { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is not repeated, validator.max_elts has no effects\n", ccTypeName, fieldName) } } if field.IsString() { p.generateStringValidator(variableName, ccTypeName, fieldName, fieldValidator) } else if p.isSupportedInt(field) { p.generateIntValidator(variableName, ccTypeName, fieldName, fieldValidator) } else if field.IsEnum() { p.generateEnumValidator(field, variableName, ccTypeName, fieldName, fieldValidator) } else if p.isSupportedFloat(field) { p.generateFloatValidator(variableName, ccTypeName, fieldName, fieldValidator) } else if field.IsBytes() { p.generateLengthValidator(variableName, ccTypeName, fieldName, fieldValidator) } else if field.IsMessage() { if repeated && nullable { variableName = "*(item)" } p.P(`if err := `, p.validatorPkg.Use(), `.CallValidatorIfExists(&(`, variableName, `)); err != nil {`) p.In() p.P(`return `, p.validatorPkg.Use(), `.FieldError("`, fieldName, `", err)`) p.Out() p.P(`}`) } if repeated { // end the repeated loop if field.IsMessage() || p.validatorWithNonRepeatedConstraint(fieldValidator) { // This internal 'if' cannot be refactored as it would change semantics with respect to the corresponding prelude 'if's p.Out() p.P(`}`) } } else if nullable { // end the if around nullable p.Out() p.P(`}`) } } p.P(`return nil`) p.Out() p.P(`}`) } func (p *plugin) generateProto3Message(file *generator.FileDescriptor, message *generator.Descriptor) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) p.P(`func (this *`, ccTypeName, `) Validate() error {`) p.In() for _, oneof := range message.OneofDecl { oneofValidator := getOneofValidatorIfAny(oneof) if oneofValidator == nil { continue } if oneofValidator.GetRequired() { oneOfName := generator.CamelCase(oneof.GetName()) p.P(`if this.Get` + oneOfName + `() == nil {`) p.In() p.P(`return `, p.validatorPkg.Use(), `.FieldError("`, oneOfName, `",`, p.fmtPkg.Use(), `.Errorf("one of the fields must be set"))`) p.Out() p.P(`}`) } } for _, field := range message.Field { fieldValidator := getFieldValidatorIfAny(field) if fieldValidator == nil && !field.IsMessage() { continue } isOneOf := field.OneofIndex != nil fieldName := p.GetOneOfFieldName(message, field) variableName := "this." + fieldName repeated := field.IsRepeated() // Golang's proto3 has no concept of unset primitive fields nullable := (gogoproto.IsNullable(field) || !gogoproto.ImportsGoGoProto(file.FileDescriptorProto)) && field.IsMessage() && !(p.useGogoImport && gogoproto.IsEmbed(field)) if p.fieldIsProto3Map(file, message, field) { p.P(`// Validation of proto3 map<> fields is unsupported.`) continue } if isOneOf { p.In() oneOfName := p.GetFieldName(message, field) oneOfType := p.OneOfTypeName(message, field) // if x, ok := m.GetType().(*OneOfMessage3_OneInt); ok { p.P(`if oneOfNester, ok := this.Get` + oneOfName + `().(* ` + oneOfType + `); ok {`) variableName = "oneOfNester." + p.GetOneOfFieldName(message, field) } if repeated { p.generateRepeatedCountValidator(variableName, ccTypeName, fieldName, fieldValidator) if field.IsMessage() || p.validatorWithNonRepeatedConstraint(fieldValidator) { p.P(`for _, item := range `, variableName, `{`) p.In() variableName = "item" } } else if fieldValidator != nil { if fieldValidator.RepeatedCountMin != nil { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is not repeated, validator.min_elts has no effects\n", ccTypeName, fieldName) } if fieldValidator.RepeatedCountMax != nil { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is not repeated, validator.max_elts has no effects\n", ccTypeName, fieldName) } } if field.IsString() { p.generateStringValidator(variableName, ccTypeName, fieldName, fieldValidator) } else if p.isSupportedInt(field) { p.generateIntValidator(variableName, ccTypeName, fieldName, fieldValidator) } else if field.IsEnum() { p.generateEnumValidator(field, variableName, ccTypeName, fieldName, fieldValidator) } else if p.isSupportedFloat(field) { p.generateFloatValidator(variableName, ccTypeName, fieldName, fieldValidator) } else if field.IsBytes() { p.generateLengthValidator(variableName, ccTypeName, fieldName, fieldValidator) } else if field.IsMessage() { if p.validatorWithMessageExists(fieldValidator) { if nullable && !repeated { p.P(`if nil == `, variableName, `{`) p.In() p.P(`return `, p.validatorPkg.Use(), `.FieldError("`, fieldName, `",`, p.fmtPkg.Use(), `.Errorf("message must exist"))`) p.Out() p.P(`}`) } else if repeated { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is repeated, validator.msg_exists has no effect\n", ccTypeName, fieldName) } else if !nullable { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v is a nullable=false, validator.msg_exists has no effect\n", ccTypeName, fieldName) } } if nullable { p.P(`if `, variableName, ` != nil {`) p.In() } else { // non-nullable fields in proto3 store actual structs, we need pointers to operate on interfaces variableName = "&(" + variableName + ")" } p.P(`if err := `, p.validatorPkg.Use(), `.CallValidatorIfExists(`, variableName, `); err != nil {`) p.In() p.P(`return `, p.validatorPkg.Use(), `.FieldError("`, fieldName, `", err)`) p.Out() p.P(`}`) if nullable { p.Out() p.P(`}`) } } if repeated && (field.IsMessage() || p.validatorWithNonRepeatedConstraint(fieldValidator)) { // end the repeated loop p.Out() p.P(`}`) } if isOneOf { // end the oneof if statement p.Out() p.P(`}`) } } p.P(`return nil`) p.Out() p.P(`}`) } func (p *plugin) generateIntValidator(variableName string, ccTypeName string, fieldName string, fv *validator.FieldValidator) { if fv.IntGt != nil { p.P(`if !(`, variableName, ` > `, fv.IntGt, `) {`) p.In() errorStr := fmt.Sprintf(`be greater than '%d'`, fv.GetIntGt()) p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } if fv.IntLt != nil { p.P(`if !(`, variableName, ` < `, fv.IntLt, `) {`) p.In() errorStr := fmt.Sprintf(`be less than '%d'`, fv.GetIntLt()) p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } } func (p *plugin) generateEnumValidator( field *descriptor.FieldDescriptorProto, variableName, ccTypeName, fieldName string, fv *validator.FieldValidator) { if fv.GetIsInEnum() { enum := p.ObjectNamed(field.GetTypeName()).(*generator.EnumDescriptor) p.P(`if _, ok := `, strings.Join(enum.TypeName(), "_"), "_name[int32(", variableName, ")]; !ok {") p.In() p.generateErrorString(variableName, fieldName, fmt.Sprintf("be a valid %s field", strings.Join(enum.TypeName(), "_")), fv) p.Out() p.P(`}`) } } func (p *plugin) generateLengthValidator(variableName string, ccTypeName string, fieldName string, fv *validator.FieldValidator) { if fv.LengthGt != nil { p.P(`if !( len(`, variableName, `) > `, fv.LengthGt, `) {`) p.In() errorStr := fmt.Sprintf(`have a length greater than '%d'`, fv.GetLengthGt()) p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } if fv.LengthLt != nil { p.P(`if !( len(`, variableName, `) < `, fv.LengthLt, `) {`) p.In() errorStr := fmt.Sprintf(`have a length smaller than '%d'`, fv.GetLengthLt()) p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } if fv.LengthEq != nil { p.P(`if !( len(`, variableName, `) == `, fv.LengthEq, `) {`) p.In() errorStr := fmt.Sprintf(`have a length equal to '%d'`, fv.GetLengthEq()) p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } } func (p *plugin) generateFloatValidator(variableName string, ccTypeName string, fieldName string, fv *validator.FieldValidator) { upperIsStrict := true lowerIsStrict := true // First check for incompatible constraints (i.e flt_lt & flt_lte both defined, etc) and determine the real limits. if fv.FloatEpsilon != nil && fv.FloatLt == nil && fv.FloatGt == nil { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v has no 'float_lt' or 'float_gt' field so setting 'float_epsilon' has no effect.", ccTypeName, fieldName) } if fv.FloatLt != nil && fv.FloatLte != nil { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v has both 'float_lt' and 'float_lte' constraints, only the strictest will be used.", ccTypeName, fieldName) strictLimit := fv.GetFloatLt() if fv.FloatEpsilon != nil { strictLimit += fv.GetFloatEpsilon() } if fv.GetFloatLte() < strictLimit { upperIsStrict = false } } else if fv.FloatLte != nil { upperIsStrict = false } if fv.FloatGt != nil && fv.FloatGte != nil { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v has both 'float_gt' and 'float_gte' constraints, only the strictest will be used.", ccTypeName, fieldName) strictLimit := fv.GetFloatGt() if fv.FloatEpsilon != nil { strictLimit -= fv.GetFloatEpsilon() } if fv.GetFloatGte() > strictLimit { lowerIsStrict = false } } else if fv.FloatGte != nil { lowerIsStrict = false } // Generate the constraint checking code. errorStr := "" compareStr := "" if fv.FloatGt != nil || fv.FloatGte != nil { compareStr = fmt.Sprint(`if !(`, variableName) if lowerIsStrict { errorStr = fmt.Sprintf(`be strictly greater than '%g'`, fv.GetFloatGt()) if fv.FloatEpsilon != nil { errorStr += fmt.Sprintf(` with a tolerance of '%g'`, fv.GetFloatEpsilon()) compareStr += fmt.Sprint(` + `, fv.GetFloatEpsilon()) } compareStr += fmt.Sprint(` > `, fv.GetFloatGt(), `) {`) } else { errorStr = fmt.Sprintf(`be greater than or equal to '%g'`, fv.GetFloatGte()) compareStr += fmt.Sprint(` >= `, fv.GetFloatGte(), `) {`) } p.P(compareStr) p.In() p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } if fv.FloatLt != nil || fv.FloatLte != nil { compareStr = fmt.Sprint(`if !(`, variableName) if upperIsStrict { errorStr = fmt.Sprintf(`be strictly lower than '%g'`, fv.GetFloatLt()) if fv.FloatEpsilon != nil { errorStr += fmt.Sprintf(` with a tolerance of '%g'`, fv.GetFloatEpsilon()) compareStr += fmt.Sprint(` - `, fv.GetFloatEpsilon()) } compareStr += fmt.Sprint(` < `, fv.GetFloatLt(), `) {`) } else { errorStr = fmt.Sprintf(`be lower than or equal to '%g'`, fv.GetFloatLte()) compareStr += fmt.Sprint(` <= `, fv.GetFloatLte(), `) {`) } p.P(compareStr) p.In() p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } } // getUUIDRegex returns a regex to validate that a string is in UUID // format. The version parameter specified the UUID version. If version is 0, // the returned regex is valid for any UUID version func getUUIDRegex(version *int32) (string, error) { if version == nil { return "", nil } else if *version < 0 || *version > 5 { return "", fmt.Errorf("UUID version should be between 0-5, Got %d", *version) } else if *version == 0 { return fmt.Sprintf(uuidPattern, "1-5"), nil } else { return fmt.Sprintf(uuidPattern, strconv.Itoa(int(*version))), nil } } func (p *plugin) generateStringValidator(variableName string, ccTypeName string, fieldName string, fv *validator.FieldValidator) { if fv.Regex != nil || fv.UuidVer != nil { if fv.UuidVer != nil { uuid, err := getUUIDRegex(fv.UuidVer) if err != nil { fmt.Fprintf(os.Stderr, "WARNING: field %v.%v error %s.\n", ccTypeName, fieldName, err) } else { fv.Regex = &uuid } } p.P(`if !`, p.regexName(ccTypeName, fieldName), `.MatchString(`, variableName, `) {`) p.In() errorStr := "be a string conforming to regex " + strconv.Quote(fv.GetRegex()) p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } if fv.StringNotEmpty != nil && fv.GetStringNotEmpty() { p.P(`if `, variableName, ` == "" {`) p.In() errorStr := "not be an empty string" p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } p.generateLengthValidator(variableName, ccTypeName, fieldName, fv) } func (p *plugin) generateRepeatedCountValidator(variableName string, ccTypeName string, fieldName string, fv *validator.FieldValidator) { if fv == nil { return } if fv.RepeatedCountMin != nil { compareStr := fmt.Sprint(`if len(`, variableName, `) < `, fv.GetRepeatedCountMin(), ` {`) p.P(compareStr) p.In() errorStr := fmt.Sprint(`contain at least `, fv.GetRepeatedCountMin(), ` elements`) p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } if fv.RepeatedCountMax != nil { compareStr := fmt.Sprint(`if len(`, variableName, `) > `, fv.GetRepeatedCountMax(), ` {`) p.P(compareStr) p.In() errorStr := fmt.Sprint(`contain at most `, fv.GetRepeatedCountMax(), ` elements`) p.generateErrorString(variableName, fieldName, errorStr, fv) p.Out() p.P(`}`) } } func (p *plugin) generateErrorString(variableName string, fieldName string, specificError string, fv *validator.FieldValidator) { if fv.GetHumanError() == "" { p.P(`return `, p.validatorPkg.Use(), `.FieldError("`, fieldName, `",`, p.fmtPkg.Use(), ".Errorf(`value '%v' must ", specificError, "`", `, `, variableName, `))`) } else { p.P(`return `, p.validatorPkg.Use(), `.FieldError("`, fieldName, `",`, p.fmtPkg.Use(), ".Errorf(`", fv.GetHumanError(), "`))") } } func (p *plugin) fieldIsProto3Map(file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto) bool { // Context from descriptor.proto // Whether the message is an automatically generated map entry type for the // maps field. // // For maps fields: // map map_field = 1; // The parsed descriptor looks like: // message MapFieldEntry { // option map_entry = true; // optional KeyType key = 1; // optional ValueType value = 2; // } // repeated MapFieldEntry map_field = 1; // // Implementations may choose not to generate the map_entry=true message, but // use a native map in the target language to hold the keys and values. // The reflection APIs in such implementions still need to work as // if the field is a repeated message field. // // NOTE: Do not set the option in .proto files. Always use the maps syntax // instead. The option should only be implicitly set by the proto compiler // parser. if field.GetType() != descriptor.FieldDescriptorProto_TYPE_MESSAGE || !field.IsRepeated() { return false } typeName := field.GetTypeName() var msg *descriptor.DescriptorProto if strings.HasPrefix(typeName, ".") { // Fully qualified case, look up in global map, must work or fail badly. msg = p.ObjectNamed(field.GetTypeName()).(*generator.Descriptor).DescriptorProto } else { // Nested, relative case. msg = file.GetNestedMessage(message.DescriptorProto, field.GetTypeName()) } return msg.GetOptions().GetMapEntry() } func (p *plugin) validatorWithMessageExists(fv *validator.FieldValidator) bool { return fv != nil && fv.MsgExists != nil && *(fv.MsgExists) } func (p *plugin) validatorWithNonRepeatedConstraint(fv *validator.FieldValidator) bool { if fv == nil { return false } // Need to use reflection in order to be future-proof for new types of constraints. v := reflect.ValueOf(*fv) for i := 0; i < v.NumField(); i++ { fieldName := v.Type().Field(i).Name // All known validators will have a pointer type and we should skip any fields // that are not pointers (i.e unknown fields, etc) as well as 'nil' pointers that // don't lead to anything. if v.Type().Field(i).Type.Kind() != reflect.Ptr || v.Field(i).IsNil() { continue } // Identify non-repeated constraints based on their name. if fieldName != "RepeatedCountMin" && fieldName != "RepeatedCountMax" { return true } } return false } func (p *plugin) regexName(ccTypeName string, fieldName string) string { return "_regex_" + ccTypeName + "_" + fieldName } golang-github-mwitkow-go-proto-validators-0.3.2/protoc-gen-govalidators/000077500000000000000000000000001515653740400264375ustar00rootroot00000000000000golang-github-mwitkow-go-proto-validators-0.3.2/protoc-gen-govalidators/BUILD.bazel000066400000000000000000000011301515653740400303100ustar00rootroot00000000000000load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") go_library( name = "go_default_library", srcs = ["main.go"], importpath = "github.com/mwitkow/go-proto-validators/protoc-gen-govalidators", visibility = ["//visibility:private"], deps = [ "//plugin:go_default_library", "@com_github_gogo_protobuf//proto:go_default_library", "@com_github_gogo_protobuf//protoc-gen-gogo/generator:go_default_library", ], ) go_binary( name = "protoc-gen-govalidators", embed = [":go_default_library"], visibility = ["//visibility:public"], ) golang-github-mwitkow-go-proto-validators-0.3.2/protoc-gen-govalidators/main.go000066400000000000000000000032411515653740400277120ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. package main import ( "io/ioutil" "os" "strconv" "strings" "github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/protoc-gen-gogo/generator" validator_plugin "github.com/mwitkow/go-proto-validators/plugin" ) func main() { gen := generator.New() data, err := ioutil.ReadAll(os.Stdin) if err != nil { gen.Error(err, "reading input") } if err := proto.Unmarshal(data, gen.Request); err != nil { gen.Error(err, "parsing input proto") } if len(gen.Request.FileToGenerate) == 0 { gen.Fail("no files to generate") } useGogoImport := false // Match parsing algorithm from Generator.CommandLineParameters for _, parameter := range strings.Split(gen.Request.GetParameter(), ",") { kvp := strings.SplitN(parameter, "=", 2) // We only care about key-value pairs where the key is "gogoimport" if len(kvp) != 2 || kvp[0] != "gogoimport" { continue } useGogoImport, err = strconv.ParseBool(kvp[1]) if err != nil { gen.Error(err, "parsing gogoimport option") } } gen.CommandLineParameters(gen.Request.GetParameter()) gen.WrapTypes() gen.SetPackageNames() gen.BuildTypeNameMap() gen.GeneratePlugin(validator_plugin.NewPlugin(useGogoImport)) for i := 0; i < len(gen.Response.File); i++ { gen.Response.File[i].Name = proto.String(strings.Replace(*gen.Response.File[i].Name, ".pb.go", ".validator.pb.go", -1)) } // Send back the results. data, err = proto.Marshal(gen.Response) if err != nil { gen.Error(err, "failed to marshal output proto") } _, err = os.Stdout.Write(data) if err != nil { gen.Error(err, "failed to write output proto") } } golang-github-mwitkow-go-proto-validators-0.3.2/scripts/000077500000000000000000000000001515653740400233555ustar00rootroot00000000000000golang-github-mwitkow-go-proto-validators-0.3.2/scripts/includes/000077500000000000000000000000001515653740400251635ustar00rootroot00000000000000golang-github-mwitkow-go-proto-validators-0.3.2/scripts/includes/deps.sh000066400000000000000000000040601515653740400264520ustar00rootroot00000000000000#!/usr/bin/env bash function install_protobuf() { if [[ -z "${PROTOBUF_VERSION:-}" ]]; then echo "Please set the version of protobuf to use via the PROTOBUF_VERSION environment variable." exit 1 fi local deps_dir os_string version version="${PROTOBUF_VERSION}" deps_dir="${PROJECT_DIR}/deps" case "$(uname -s | tr "[:upper:]" "[:lower:]")" in linux) os_string="linux" ;; darwin) os_string="osx" ;; *) echo "This platform is not supported for running this script." exit 1 ;; esac if [[ ! -e "${deps_dir}/${version}.zip" ]]; then echo "Downloading and installing protoc ${version}." mkdir -p "${deps_dir}" pushd "${deps_dir}" || exit 1 rm -rf "${version}.zip" "${version}.zip.tmp" "bin" "include" wget "https://github.com/google/protobuf/releases/download/v${version}/protoc-${version}-${os_string}-x86_64.zip" -O "${version}.zip.tmp" unzip -o "${version}.zip.tmp" chmod 755 "bin/protoc" mv "${version}.zip.tmp" "${version}.zip" popd || exit 1 else echo "Reusing existing protoc ${version}." fi } function setup_proto_deps() { local dep dep_dir dep_location proto_deps dep_dir="${PROJECT_DIR}/deps" proto_deps=( "github.com/gogo/protobuf" "github.com/golang/protobuf" "github.com/mwitkow/go-proto-validators" ) # Set up the target directory for symlinking in dependencies. mkdir -p "${dep_dir}" # Ensure the module dependencies are available go mod download for dep in "${proto_deps[@]}"; do dep_location="$(go list -m -json "${dep}" | jq -rM '.Dir')" mkdir -p "${dep_dir}/$(dirname "${dep}")" rm -f "${dep_dir}/${dep}" ln -sf "${dep_location}" "${dep_dir}/${dep}" done go install github.com/gogo/protobuf/protoc-gen-gogo go install github.com/golang/protobuf/protoc-gen-go PATH="${GOBIN:-"${HOME}/go/bin"}:${PATH}" export PATH } golang-github-mwitkow-go-proto-validators-0.3.2/scripts/prepare-deps.sh000066400000000000000000000003071515653740400263000ustar00rootroot00000000000000#!/usr/bin/env bash set -e -u -o pipefail PROJECT_DIR="$(dirname "${BASH_SOURCE[0]}")/.." cd "${PROJECT_DIR}" export PROJECT_DIR source scripts/includes/deps.sh install_protobuf setup_proto_deps golang-github-mwitkow-go-proto-validators-0.3.2/test/000077500000000000000000000000001515653740400226455ustar00rootroot00000000000000golang-github-mwitkow-go-proto-validators-0.3.2/test/.gitignore000066400000000000000000000000201515653740400246250ustar00rootroot00000000000000*.pb.go Makefilegolang-github-mwitkow-go-proto-validators-0.3.2/test/BUILD.bazel000066400000000000000000000015221515653740400245230ustar00rootroot00000000000000load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "proto2", srcs = ["validator_proto2.proto"], deps = [ "//:validator_proto", "@gogo_special_proto//github.com/gogo/protobuf/gogoproto", ], visibility = ["//test:__subpackages__"], ) proto_library( name = "proto3", srcs = ["validator_proto3.proto"], deps = [ "//:validator_proto", "@gogo_special_proto//github.com/gogo/protobuf/gogoproto", ], visibility = ["//test:__subpackages__"], ) proto_library( name = "proto3_oneof", srcs = ["validator_proto3_oneof.proto"], deps = [ "//:validator_proto", ], visibility = ["//test:__subpackages__"], ) proto_library( name = "proto3_map", srcs = ["validator_proto3_map.proto"], visibility = ["//test:__subpackages__"], ) golang-github-mwitkow-go-proto-validators-0.3.2/test/gogo/000077500000000000000000000000001515653740400236005ustar00rootroot00000000000000golang-github-mwitkow-go-proto-validators-0.3.2/test/gogo/BUILD.bazel000066400000000000000000000012411515653740400254540ustar00rootroot00000000000000load("@io_bazel_rules_go//go:def.bzl", "go_test") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") go_proto_library( name = "gogo_proto", importpath = "dummy", protos = [ "//test:proto2", "//test:proto3", "//test:proto3_oneof", "//test:proto3_map", ], compilers = [ "//:gogo_proto_validators", "@io_bazel_rules_go//proto:gogo_proto", ], visibility = [":__pkg__"] ) go_test( name = "go_default_test", importpath = "dummy", srcs = ["validator_test.go"], embed = [":gogo_proto"], deps = [ "@com_github_stretchr_testify//assert:go_default_library", ], ) golang-github-mwitkow-go-proto-validators-0.3.2/test/gogo/validator_test.go000066400000000000000000000620221515653740400271550ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. package validatortest import ( fmt "fmt" "strings" "testing" "github.com/stretchr/testify/assert" ) var ( stableBytes = make([]byte, 12) ) const ( uuid4 = "fbe91ff5-fee7-40d3-89a8-f3db6cf210be" uuid1 = "66bb25e2-2e0d-11e9-b210-d663bd873d93" ) func buildProto3(someString string, someInt uint32, identifier string, someValue int64, someDoubleStrict float64, someFloatStrict float32, someDouble float64, someFloat float32, nonEmptyString string, repeatedCount uint32, someStringLength string, someBytes []byte, optionalUUIDAny, uuid4 string, someEnum int32, someEmbeddedEnum int32) *ValidatorMessage3 { goodEmbeddedProto3 := &ValidatorMessage3_EmbeddedMessage{ Identifier: identifier, SomeValue: someValue, } goodProto3 := &ValidatorMessage3{ SomeString: someString, SomeStringRep: []string{someString, "xyz34"}, SomeStringNoQuotes: someString, SomeStringUnescaped: someString, SomeInt: someInt, SomeIntRep: []uint32{someInt, 12, 13, 14, 15, 16}, SomeIntRepNonNull: []uint32{someInt, 102}, SomeEmbedded: nil, SomeEmbeddedNonNullable: *goodEmbeddedProto3, SomeEmbeddedExists: goodEmbeddedProto3, SomeEmbeddedRep: []*ValidatorMessage3_EmbeddedMessage{goodEmbeddedProto3}, SomeEmbeddedRepNonNullable: []ValidatorMessage3_EmbeddedMessage{*goodEmbeddedProto3}, StrictSomeDouble: someDoubleStrict, StrictSomeDoubleRep: []float64{someDoubleStrict, 0.5, 0.55, 0.6}, StrictSomeDoubleRepNonNull: []float64{someDoubleStrict, 0.5, 0.55, 0.6}, StrictSomeFloat: someFloatStrict, StrictSomeFloatRep: []float32{someFloatStrict, 0.5, 0.55, 0.6}, StrictSomeFloatRepNonNull: []float32{someFloatStrict, 0.5, 0.55, 0.6}, SomeDouble: someDouble, SomeDoubleRep: []float64{someDouble, 0.5, 0.55, 0.6}, SomeDoubleRepNonNull: []float64{someDouble, 0.5, 0.55, 0.6}, SomeFloat: someFloat, SomeFloatRep: []float32{someFloat, 0.5, 0.55, 0.6}, SomeFloatRepNonNull: []float32{someFloat, 0.5, 0.55, 0.6}, SomeNonEmptyString: nonEmptyString, SomeStringEqReq: someStringLength, SomeStringLtReq: someStringLength, SomeStringGtReq: someStringLength, SomeBytesLtReq: someBytes, SomeBytesGtReq: someBytes, SomeBytesEqReq: someBytes, RepeatedBaseType: []int32{}, UUIDAny: optionalUUIDAny, UUID4NotEmpty: uuid4, SomeEnum: EnumProto3(someEnum), SomeEmbeddedEnum: ValidatorMessage3_EmbeddedEnum(someEmbeddedEnum), ValidatorMessage3_EmbeddedMessage: *goodEmbeddedProto3, } goodProto3.Repeated = make([]int32, repeatedCount) return goodProto3 } func buildProto2(someString string, someInt uint32, identifier string, someValue int64, someDoubleStrict float64, someFloatStrict float32, someDouble float64, someFloat float32, nonEmptyString string, repeatedCount uint32, someStringLength string, someBytes []byte, optionalUUIDAny, uuid5 string, someEnum int32, someEmbeddedEnum int32) *ValidatorMessage { goodEmbeddedProto2 := &ValidatorMessage_EmbeddedMessage{ Identifier: &identifier, SomeValue: &someValue, } goodProto2 := &ValidatorMessage{ StringReq: &someString, StringReqNonNull: someString, StringOpt: nil, StringOptNonNull: someString, StringUnescaped: &someString, IntReq: &someInt, IntReqNonNull: someInt, IntRep: []uint32{someInt, 12, 13, 14, 15, 16}, IntRepNonNull: []uint32{someInt, 12, 13, 14, 15, 16}, EmbeddedReq: goodEmbeddedProto2, EmbeddedNonNull: *goodEmbeddedProto2, EmbeddedRep: []*ValidatorMessage_EmbeddedMessage{goodEmbeddedProto2}, EmbeddedRepNonNullable: []ValidatorMessage_EmbeddedMessage{*goodEmbeddedProto2}, StrictSomeDoubleReq: &someDoubleStrict, StrictSomeDoubleReqNonNull: someDoubleStrict, StrictSomeDoubleRep: []float64{someDoubleStrict, 0.5, 0.55, 0.6}, StrictSomeDoubleRepNonNull: []float64{someDoubleStrict, 0.5, 0.55, 0.6}, StrictSomeFloatReq: &someFloatStrict, StrictSomeFloatReqNonNull: someFloatStrict, StrictSomeFloatRep: []float32{someFloatStrict, 0.5, 0.55, 0.6}, StrictSomeFloatRepNonNull: []float32{someFloatStrict, 0.5, 0.55, 0.6}, SomeDoubleReq: &someDouble, SomeDoubleReqNonNull: someDouble, SomeDoubleRep: []float64{someDouble, 0.5, 0.55, 0.6}, SomeDoubleRepNonNull: []float64{someDouble, 0.5, 0.55, 0.6}, SomeFloatReq: &someFloat, SomeFloatReqNonNull: someFloat, SomeFloatRep: []float32{someFloat, 0.5, 0.55, 0.6}, SomeFloatRepNonNull: []float32{someFloat, 0.5, 0.55, 0.6}, SomeNonEmptyString: &nonEmptyString, SomeStringEqReq: &someStringLength, SomeStringLtReq: &someStringLength, SomeStringGtReq: &someStringLength, SomeBytesLtReq: someBytes, SomeBytesGtReq: someBytes, SomeBytesEqReq: someBytes, RepeatedBaseType: []int32{}, UUIDAny: &optionalUUIDAny, UUID4NotEmpty: &uuid5, SomeEnum: (*EnumProto2)(&someEnum), SomeEmbeddedEnum: (*ValidatorMessage_EmbeddedEnum)(&someEmbeddedEnum), } goodProto2.Repeated = make([]int32, repeatedCount) return goodProto2 } func TestGoodProto3(t *testing.T) { var err error goodProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 1, 1) err = goodProto3.Validate() if err != nil { t.Fatalf("unexpected fail in validator: %v", err) } } func TestGoodProto2(t *testing.T) { var err error goodProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 1, 1) err = goodProto2.Validate() if err != nil { t.Fatalf("unexpected fail in validator: %v", err) } } func TestStringRegex(t *testing.T) { tooLong1Proto3 := buildProto3("toolong", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooLong1Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooLong1Proto2 := buildProto2("toolong", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooLong1Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooLong2Proto3 := buildProto3("-%ab", 11, "bad#", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooLong2Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooLong2Proto2 := buildProto2("-%ab", 11, "bad#", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooLong2Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } } func TestIntLowerBounds(t *testing.T) { lowerThan10Proto3 := buildProto3("-%ab", 9, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan10Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan10Proto2 := buildProto2("-%ab", 9, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan10Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan0Proto3 := buildProto3("-%ab", 11, "abba", -1, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan0Proto2 := buildProto2("-%ab", 11, "abba", -1, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } } func TestIntUpperBounds(t *testing.T) { greaterThan100Proto3 := buildProto3("-%ab", 11, "abba", 101, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan100Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan100Proto2 := buildProto2("-%ab", 11, "abba", 101, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan100Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } } func TestDoubleStrictLowerBounds(t *testing.T) { lowerThan035EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.3, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan035EpsilonProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan035EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.3, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan035EpsilonProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan035EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.300000001, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan035EpsilonProto3.Validate() != nil { t.Fatalf("unexpected fail in validator") } greaterThan035EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.300000001, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan035EpsilonProto2.Validate() != nil { t.Fatalf("unexpected fail in validator") } } func TestDoubleStrictUpperBounds(t *testing.T) { greaterThan065EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.70000000001, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan065EpsilonProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan065EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.70000000001, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan065EpsilonProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan065EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.6999999999, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan065EpsilonProto3.Validate() != nil { t.Fatalf("unexpected fail in validator") } lowerThan065EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.6999999999, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan065EpsilonProto2.Validate() != nil { t.Fatalf("unexpected fail in validator") } } func TestFloatStrictLowerBounds(t *testing.T) { lowerThan035EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.2999999, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan035EpsilonProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan035EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.2999999, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan035EpsilonProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan035EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.3000001, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := greaterThan035EpsilonProto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } greaterThan035EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.3000001, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := greaterThan035EpsilonProto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestFloatStrictUpperBounds(t *testing.T) { greaterThan065EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.7000001, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan065EpsilonProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan065EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.7000001, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan065EpsilonProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan065EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.6999999, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := lowerThan065EpsilonProto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } lowerThan065EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.6999999, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := lowerThan065EpsilonProto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestDoubleNonStrictLowerBounds(t *testing.T) { lowerThan0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.2499999, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.2499999, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } equalTo0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.25, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } equalTo0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.25, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestDoubleNonStrictUpperBounds(t *testing.T) { higherThan1Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.75111111, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if higherThan1Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } higherThan1Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.75111111, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if higherThan1Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } equalTo0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.75, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } equalTo0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.75, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestFloatNonStrictLowerBounds(t *testing.T) { lowerThan0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.2499999, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.2499999, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } equalTo0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.25, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } equalTo0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.25, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestFloatNonStrictUpperBounds(t *testing.T) { higherThan1Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.75111111, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if higherThan1Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } higherThan1Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.75111111, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if higherThan1Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } equalTo0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.75, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } equalTo0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.75, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestStringNonEmpty(t *testing.T) { emptyStringProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if emptyStringProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } emptyStringProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if emptyStringProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } nonEmptyStringProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := nonEmptyStringProto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } nonEmptyStringProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := nonEmptyStringProto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestRepeatedEltsCount(t *testing.T) { notEnoughEltsProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 1, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if notEnoughEltsProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } notEnoughEltsProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 1, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if notEnoughEltsProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooManyEltsProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 14, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooManyEltsProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooManyEltsProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 14, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooManyEltsProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } validEltsCountProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := validEltsCountProto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } validEltsCountProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := validEltsCountProto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestMsgExist(t *testing.T) { someProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) someProto3.SomeEmbedded = nil if err := someProto3.Validate(); err != nil { t.Fatalf("validate shouldn't fail on missing SomeEmbedded, not annotated") } someProto3.SomeEmbeddedExists = nil if err := someProto3.Validate(); err == nil { t.Fatalf("expected fail due to lacking SomeEmbeddedExists") } else if !strings.HasPrefix(err.Error(), "invalid field SomeEmbeddedExists:") { t.Fatalf("expected fieldError, got '%v'", err) } } func TestValueIsInEnum(t *testing.T) { outOfTopLevelEnumProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 2, 0) if err := outOfTopLevelEnumProto3.Validate(); err == nil { t.Fatalf("expected fail in validator, but it didn't happen") } outOfTopLevelEnumProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 2, 0) if err := outOfTopLevelEnumProto2.Validate(); err == nil { t.Fatalf("expected fail in validator, but it didn't happen") } outOfEmbeddedEnumProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 2) if err := outOfEmbeddedEnumProto3.Validate(); err == nil { t.Fatalf("expected fail in validator, but it didn't happen") } outOfEmbeddedEnumProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 2) if err := outOfEmbeddedEnumProto2.Validate(); err == nil { t.Fatalf("expected fail in validator, but it didn't happen") } } func TestNestedError3(t *testing.T) { someProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) someProto3.SomeEmbeddedExists.SomeValue = 101 // should be less than 101 if err := someProto3.Validate(); err == nil { t.Fatalf("expected fail due to nested SomeEmbeddedExists.SomeValue being wrong") } else if !strings.HasPrefix(err.Error(), "invalid field SomeEmbeddedExists.SomeValue:") { t.Fatalf("expected fieldError, got '%v'", err) } } func TestCustomError_Proto3(t *testing.T) { someProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) someProto3.CustomErrorInt = 30 expectedErr := "invalid field CustomErrorInt: My Custom Error" if err := someProto3.Validate(); err == nil { t.Fatalf("validate should fail on missing CustomErrorInt") } else if err.Error() != expectedErr { t.Fatalf("validation error should be '%s' but was '%s'", expectedErr, err.Error()) } } func TestMapAlwaysPassesUntilFixedProperly(t *testing.T) { example := &ValidatorMapMessage3{} if err := example.Validate(); err != nil { t.Fatalf("map validators should always pass") } } func TestOneOf_Required(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, } err := example.Validate() assert.Error(t, err, "oneof.required should fail if none of the oneof fields are set") assert.Contains(t, err.Error(), "Something", "error must err on the Something field") } func TestOneOf_NestedMessage(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, Type: &OneOfMessage3_OneMsg{ OneMsg: &ExternalMsg{ Identifier: "999", // bad SomeValue: 99, // good }, }, Something: &OneOfMessage3_ThreeInt{ ThreeInt: 100, // > 20 }, } err := example.Validate() assert.Error(t, err, "nested message in oneof should fail validation on ExternalMsg") assert.Contains(t, err.Error(), "OneMsg.Identifier", "error must err on the ExternalMsg.Identifier") } func TestOneOf_NestedInt(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, Type: &OneOfMessage3_OneMsg{ OneMsg: &ExternalMsg{ Identifier: "abba", // good SomeValue: 99, // good }, }, Something: &OneOfMessage3_ThreeInt{ ThreeInt: 19, // > 20 }, } err := example.Validate() assert.Error(t, err, "nested message in oneof should fail validation on ThreeInt") assert.Contains(t, err.Error(), "ThreeInt", "error must err on the ThreeInt.ThreeInt") } func TestOneOf_Passes(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, Type: &OneOfMessage3_OneMsg{ OneMsg: &ExternalMsg{ Identifier: "abba", // good SomeValue: 99, // good }, }, Something: &OneOfMessage3_FourInt{ FourInt: 101, // > 101 }, } err := example.Validate() assert.NoError(t, err, "This message should pass all validation") } func TestOneOf_Regex(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, Something: &OneOfMessage3_FiveRegex{ FiveRegex: "11", // fail }, } err := example.Validate() assert.Error(t, err, "regex applied to oneof field should fail validation on FiveRegex") assert.Contains(t, err.Error(), "FiveRegex", "error must err on the FiveRegex") example = &OneOfMessage3{ SomeInt: 30, Something: &OneOfMessage3_FiveRegex{ FiveRegex: "aaa", // pass }, } err = example.Validate() assert.NoError(t, err, "This message should pass all validation") } func TestUUID4Validation(t *testing.T) { testcases := []struct { uuid string fail bool }{ { uuid: uuid1, fail: true, }, { uuid: uuid4, fail: false, }, { uuid: "", fail: true, }, { uuid: "66bb25e2-2e0d", fail: true, }, { uuid: "1234abcd", fail: true, }, } for _, tc := range testcases { t.Run(fmt.Sprintf("proto2 uuid '%s'", tc.uuid), func(t *testing.T) { msg := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, tc.uuid, 0, 0) err := msg.Validate() failed := err != nil if tc.fail != failed { t.Errorf("Expected validation failure: %t, but got %t, err: %v", tc.fail, failed, err) } }) t.Run(fmt.Sprintf("proto3 uuid '%s'", tc.uuid), func(t *testing.T) { msg := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, tc.uuid, 0, 0) err := msg.Validate() failed := err != nil if tc.fail != failed { t.Errorf("Expected validation failure: %t, but got %t, err: %v", tc.fail, failed, err) } }) } } golang-github-mwitkow-go-proto-validators-0.3.2/test/golang/000077500000000000000000000000001515653740400241145ustar00rootroot00000000000000golang-github-mwitkow-go-proto-validators-0.3.2/test/golang/BUILD.bazel000066400000000000000000000013601515653740400257720ustar00rootroot00000000000000load("@io_bazel_rules_go//go:def.bzl", "go_test") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") go_proto_library( name = "go_proto", importpath = "dummy", protos = [ "//test:proto2", "//test:proto3", "//test:proto3_oneof", "//test:proto3_map", ], compilers = [ "//:go_proto_validators", "@io_bazel_rules_go//proto:go_proto", ], deps = [ "@com_github_gogo_protobuf//gogoproto:go_default_library", ], visibility = [":__pkg__"] ) go_test( name = "go_default_test", importpath = "dummy", srcs = ["validator_test.go"], embed = [":go_proto"], deps = [ "@com_github_stretchr_testify//assert:go_default_library", ], ) golang-github-mwitkow-go-proto-validators-0.3.2/test/golang/validator_test.go000066400000000000000000000641411515653740400274750ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. package validatortest import ( fmt "fmt" "strings" "testing" "github.com/stretchr/testify/assert" ) var ( stableBytes = make([]byte, 12) ) const ( uuid4 = "fbe91ff5-fee7-40d3-89a8-f3db6cf210be" uuid1 = "66bb25e2-2e0d-11e9-b210-d663bd873d93" ) func buildProto3(someString string, someInt uint32, identifier string, someValue int64, someDoubleStrict float64, someFloatStrict float32, someDouble float64, someFloat float32, nonEmptyString string, repeatedCount uint32, someStringLength string, someBytes []byte, optionalUUIDAny, uuid4 string, someEnum int32, someEmbeddedEnum int32) *ValidatorMessage3 { goodEmbeddedProto3 := &ValidatorMessage3_EmbeddedMessage{ Identifier: identifier, SomeValue: someValue, } goodProto3 := &ValidatorMessage3{ SomeString: someString, SomeStringRep: []string{someString, "xyz34"}, SomeStringNoQuotes: someString, SomeStringUnescaped: someString, SomeInt: someInt, SomeIntRep: []uint32{someInt, 12, 13, 14, 15, 16}, SomeIntRepNonNull: []uint32{someInt, 102}, SomeEmbedded: nil, SomeEmbeddedNonNullable: goodEmbeddedProto3, SomeEmbeddedExists: goodEmbeddedProto3, SomeEmbeddedRep: []*ValidatorMessage3_EmbeddedMessage{goodEmbeddedProto3}, SomeEmbeddedRepNonNullable: []*ValidatorMessage3_EmbeddedMessage{goodEmbeddedProto3}, StrictSomeDouble: someDoubleStrict, StrictSomeDoubleRep: []float64{someDoubleStrict, 0.5, 0.55, 0.6}, StrictSomeDoubleRepNonNull: []float64{someDoubleStrict, 0.5, 0.55, 0.6}, StrictSomeFloat: someFloatStrict, StrictSomeFloatRep: []float32{someFloatStrict, 0.5, 0.55, 0.6}, StrictSomeFloatRepNonNull: []float32{someFloatStrict, 0.5, 0.55, 0.6}, SomeDouble: someDouble, SomeDoubleRep: []float64{someDouble, 0.5, 0.55, 0.6}, SomeDoubleRepNonNull: []float64{someDouble, 0.5, 0.55, 0.6}, SomeFloat: someFloat, SomeFloatRep: []float32{someFloat, 0.5, 0.55, 0.6}, SomeFloatRepNonNull: []float32{someFloat, 0.5, 0.55, 0.6}, SomeNonEmptyString: nonEmptyString, SomeStringEqReq: someStringLength, SomeStringLtReq: someStringLength, SomeStringGtReq: someStringLength, SomeBytesLtReq: someBytes, SomeBytesGtReq: someBytes, SomeBytesEqReq: someBytes, RepeatedBaseType: []int32{}, UUIDAny: optionalUUIDAny, UUID4NotEmpty: uuid4, SomeEnum: EnumProto3(someEnum), SomeEmbeddedEnum: ValidatorMessage3_EmbeddedEnum(someEmbeddedEnum), SomeGogoEmbedded: goodEmbeddedProto3, } goodProto3.Repeated = make([]int32, repeatedCount) return goodProto3 } func buildProto2(someString string, someInt uint32, identifier string, someValue int64, someDoubleStrict float64, someFloatStrict float32, someDouble float64, someFloat float32, nonEmptyString string, repeatedCount uint32, someStringLength string, someBytes []byte, optionalUUIDAny, uuid5 string, someEnum int32, someEmbeddedEnum int32) *ValidatorMessage { goodEmbeddedProto2 := &ValidatorMessage_EmbeddedMessage{ Identifier: &identifier, SomeValue: &someValue, } goodProto2 := &ValidatorMessage{ StringReq: &someString, StringReqNonNull: &someString, StringOpt: nil, StringOptNonNull: &someString, StringUnescaped: &someString, IntReq: &someInt, IntReqNonNull: &someInt, IntRep: []uint32{someInt, 12, 13, 14, 15, 16}, IntRepNonNull: []uint32{someInt, 12, 13, 14, 15, 16}, EmbeddedReq: goodEmbeddedProto2, EmbeddedNonNull: goodEmbeddedProto2, EmbeddedRep: []*ValidatorMessage_EmbeddedMessage{goodEmbeddedProto2}, EmbeddedRepNonNullable: []*ValidatorMessage_EmbeddedMessage{goodEmbeddedProto2}, StrictSomeDoubleReq: &someDoubleStrict, StrictSomeDoubleReqNonNull: &someDoubleStrict, StrictSomeDoubleRep: []float64{someDoubleStrict, 0.5, 0.55, 0.6}, StrictSomeDoubleRepNonNull: []float64{someDoubleStrict, 0.5, 0.55, 0.6}, StrictSomeFloatReq: &someFloatStrict, StrictSomeFloatReqNonNull: &someFloatStrict, StrictSomeFloatRep: []float32{someFloatStrict, 0.5, 0.55, 0.6}, StrictSomeFloatRepNonNull: []float32{someFloatStrict, 0.5, 0.55, 0.6}, SomeDoubleReq: &someDouble, SomeDoubleReqNonNull: &someDouble, SomeDoubleRep: []float64{someDouble, 0.5, 0.55, 0.6}, SomeDoubleRepNonNull: []float64{someDouble, 0.5, 0.55, 0.6}, SomeFloatReq: &someFloat, SomeFloatReqNonNull: &someFloat, SomeFloatRep: []float32{someFloat, 0.5, 0.55, 0.6}, SomeFloatRepNonNull: []float32{someFloat, 0.5, 0.55, 0.6}, SomeNonEmptyString: &nonEmptyString, SomeStringEqReq: &someStringLength, SomeStringLtReq: &someStringLength, SomeStringGtReq: &someStringLength, SomeBytesLtReq: someBytes, SomeBytesGtReq: someBytes, SomeBytesEqReq: someBytes, RepeatedBaseType: []int32{}, UUIDAny: &optionalUUIDAny, UUID4NotEmpty: &uuid5, SomeEnum: (*EnumProto2)(&someEnum), SomeEmbeddedEnum: (*ValidatorMessage_EmbeddedEnum)(&someEmbeddedEnum), } goodProto2.Repeated = make([]int32, repeatedCount) return goodProto2 } func TestGoodProto3(t *testing.T) { var err error goodProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 1, 1) err = goodProto3.Validate() if err != nil { t.Fatalf("unexpected fail in validator: %v", err) } } func TestGoodProto2(t *testing.T) { var err error goodProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 1, 1) err = goodProto2.Validate() if err != nil { t.Fatalf("unexpected fail in validator: %v", err) } } func TestStringRegex(t *testing.T) { tooLong1Proto3 := buildProto3("toolong", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooLong1Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooLong1Proto2 := buildProto2("toolong", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooLong1Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooLong2Proto3 := buildProto3("-%ab", 11, "bad#", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooLong2Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooLong2Proto2 := buildProto2("-%ab", 11, "bad#", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooLong2Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } } func TestIntLowerBounds(t *testing.T) { lowerThan10Proto3 := buildProto3("-%ab", 9, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan10Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan10Proto2 := buildProto2("-%ab", 9, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan10Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan0Proto3 := buildProto3("-%ab", 11, "abba", -1, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan0Proto2 := buildProto2("-%ab", 11, "abba", -1, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } } func TestIntUpperBounds(t *testing.T) { greaterThan100Proto3 := buildProto3("-%ab", 11, "abba", 101, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan100Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan100Proto2 := buildProto2("-%ab", 11, "abba", 101, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan100Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } } func TestDoubleStrictLowerBounds(t *testing.T) { lowerThan035EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.3, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan035EpsilonProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan035EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.3, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan035EpsilonProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan035EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.300000001, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan035EpsilonProto3.Validate() != nil { t.Fatalf("unexpected fail in validator") } greaterThan035EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.300000001, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan035EpsilonProto2.Validate() != nil { t.Fatalf("unexpected fail in validator") } } func TestDoubleStrictUpperBounds(t *testing.T) { greaterThan065EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.70000000001, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan065EpsilonProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan065EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.70000000001, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan065EpsilonProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan065EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.6999999999, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan065EpsilonProto3.Validate() != nil { t.Fatalf("unexpected fail in validator") } lowerThan065EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.6999999999, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan065EpsilonProto2.Validate() != nil { t.Fatalf("unexpected fail in validator") } } func TestFloatStrictLowerBounds(t *testing.T) { lowerThan035EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.2999999, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan035EpsilonProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan035EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.2999999, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan035EpsilonProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan035EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.3000001, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := greaterThan035EpsilonProto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } greaterThan035EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.3000001, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := greaterThan035EpsilonProto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestFloatStrictUpperBounds(t *testing.T) { greaterThan065EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.7000001, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan065EpsilonProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } greaterThan065EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.7000001, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if greaterThan065EpsilonProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan065EpsilonProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.6999999, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := lowerThan065EpsilonProto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } lowerThan065EpsilonProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.6999999, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := lowerThan065EpsilonProto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestDoubleNonStrictLowerBounds(t *testing.T) { lowerThan0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.2499999, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.2499999, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } equalTo0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.25, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } equalTo0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.25, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestDoubleNonStrictUpperBounds(t *testing.T) { higherThan1Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.75111111, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if higherThan1Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } higherThan1Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.75111111, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if higherThan1Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } equalTo0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.75, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } equalTo0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.75, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestFloatNonStrictLowerBounds(t *testing.T) { lowerThan0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.2499999, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } lowerThan0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.2499999, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if lowerThan0Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } equalTo0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.25, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } equalTo0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.25, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestFloatNonStrictUpperBounds(t *testing.T) { higherThan1Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.75111111, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if higherThan1Proto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } higherThan1Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.75111111, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if higherThan1Proto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } equalTo0Proto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.75, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } equalTo0Proto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.75, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := equalTo0Proto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestStringNonEmpty(t *testing.T) { emptyStringProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if emptyStringProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } emptyStringProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if emptyStringProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } nonEmptyStringProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := nonEmptyStringProto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } nonEmptyStringProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := nonEmptyStringProto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestRepeatedEltsCount(t *testing.T) { notEnoughEltsProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 1, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if notEnoughEltsProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } notEnoughEltsProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 1, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if notEnoughEltsProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooManyEltsProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 14, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooManyEltsProto3.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } tooManyEltsProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 14, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if tooManyEltsProto2.Validate() == nil { t.Fatalf("expected fail in validator, but it didn't happen") } validEltsCountProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := validEltsCountProto3.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } validEltsCountProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := validEltsCountProto2.Validate(); err != nil { t.Fatalf("unexpected fail in validator %v", err) } } func TestMsgExist(t *testing.T) { someProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) someProto3.SomeEmbedded = nil if err := someProto3.Validate(); err != nil { t.Fatalf("validate shouldn't fail on missing SomeEmbedded, not annotated") } someProto3.SomeEmbeddedExists = nil if err := someProto3.Validate(); err == nil { t.Fatalf("expected fail due to lacking SomeEmbeddedExists") } else if !strings.HasPrefix(err.Error(), "invalid field SomeEmbeddedExists:") { t.Fatalf("expected fieldError, got '%v'", err) } } func TestStringLengthValidator(t *testing.T) { StringLengthErrorProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "abc456", stableBytes, uuid1, uuid4, 0, 0) if err := StringLengthErrorProto3.Validate(); err == nil { t.Fatalf("validate shouldn't fail on error length") } StringLengthSuccess := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := StringLengthSuccess.Validate(); err != nil { t.Fatalf("validate shouldn't fail on equal length") } } func TestBytesLengthValidator(t *testing.T) { StringLengthErrorProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "abc456", []byte("anc"), uuid1, uuid4, 0, 0) if err := StringLengthErrorProto3.Validate(); err == nil { t.Fatalf("validate shouldn't fail on error length") } StringLengthSuccess := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) if err := StringLengthSuccess.Validate(); err != nil { t.Fatalf("validate shouldn't fail on equal length") } } func TestValueIsInEnum(t *testing.T) { outOfTopLevelEnumProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 2, 0) if err := outOfTopLevelEnumProto3.Validate(); err == nil { t.Fatalf("expected fail in validator, but it didn't happen") } outOfTopLevelEnumProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 2, 0) if err := outOfTopLevelEnumProto2.Validate(); err == nil { t.Fatalf("expected fail in validator, but it didn't happen") } outOfEmbeddedEnumProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 2) if err := outOfEmbeddedEnumProto3.Validate(); err == nil { t.Fatalf("expected fail in validator, but it didn't happen") } outOfEmbeddedEnumProto2 := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 2) if err := outOfEmbeddedEnumProto2.Validate(); err == nil { t.Fatalf("expected fail in validator, but it didn't happen") } } func TestNestedError3(t *testing.T) { someProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) someProto3.SomeEmbeddedExists.SomeValue = 101 // should be less than 101 if err := someProto3.Validate(); err == nil { t.Fatalf("expected fail due to nested SomeEmbeddedNonNullable.SomeValue being wrong") } else if !strings.HasPrefix(err.Error(), "invalid field SomeEmbeddedNonNullable.SomeValue:") { t.Fatalf("expected fieldError, got '%v'", err) } } func TestCustomError_Proto3(t *testing.T) { someProto3 := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, uuid4, 0, 0) someProto3.CustomErrorInt = 30 expectedErr := "invalid field CustomErrorInt: My Custom Error" if err := someProto3.Validate(); err == nil { t.Fatalf("validate should fail on missing CustomErrorInt") } else if err.Error() != expectedErr { t.Fatalf("validation error should be '%s' but was '%s'", expectedErr, err.Error()) } } func TestMapAlwaysPassesUntilFixedProperly(t *testing.T) { example := &ValidatorMapMessage3{} if err := example.Validate(); err != nil { t.Fatalf("map validators should always pass") } } func TestOneOf_Required(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, } err := example.Validate() assert.Error(t, err, "oneof.required should fail if none of the oneof fields are set") assert.Contains(t, err.Error(), "Something", "error must err on the Something field") } func TestOneOf_NestedMessage(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, Type: &OneOfMessage3_OneMsg{ OneMsg: &ExternalMsg{ Identifier: "999", // bad SomeValue: 99, // good }, }, Something: &OneOfMessage3_ThreeInt{ ThreeInt: 100, // > 20 }, } err := example.Validate() assert.Error(t, err, "nested message in oneof should fail validation on ExternalMsg") assert.Contains(t, err.Error(), "OneMsg.Identifier", "error must err on the ExternalMsg.Identifier") } func TestOneOf_NestedInt(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, Type: &OneOfMessage3_OneMsg{ OneMsg: &ExternalMsg{ Identifier: "abba", // good SomeValue: 99, // good }, }, Something: &OneOfMessage3_ThreeInt{ ThreeInt: 19, // > 20 }, } err := example.Validate() assert.Error(t, err, "nested message in oneof should fail validation on ThreeInt") assert.Contains(t, err.Error(), "ThreeInt", "error must err on the ThreeInt.ThreeInt") } func TestOneOf_Passes(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, Type: &OneOfMessage3_OneMsg{ OneMsg: &ExternalMsg{ Identifier: "abba", // good SomeValue: 99, // good }, }, Something: &OneOfMessage3_FourInt{ FourInt: 101, // > 101 }, } err := example.Validate() assert.NoError(t, err, "This message should pass all validation") } func TestOneOf_Regex(t *testing.T) { example := &OneOfMessage3{ SomeInt: 30, Something: &OneOfMessage3_FiveRegex{ FiveRegex: "11", // fail }, } err := example.Validate() assert.Error(t, err, "regex applied to oneof field should fail validation on FiveRegex") assert.Contains(t, err.Error(), "FiveRegex", "error must err on the FiveRegex") example = &OneOfMessage3{ SomeInt: 30, Something: &OneOfMessage3_FiveRegex{ FiveRegex: "aaa", // pass }, } err = example.Validate() assert.NoError(t, err, "This message should pass all validation") } func TestUUID4Validation(t *testing.T) { testcases := []struct { uuid string fail bool }{ { uuid: uuid1, fail: true, }, { uuid: uuid4, fail: false, }, { uuid: "", fail: true, }, { uuid: "66bb25e2-2e0d", fail: true, }, { uuid: "1234abcd", fail: true, }, } for _, tc := range testcases { t.Run(fmt.Sprintf("proto2 uuid '%s'", tc.uuid), func(t *testing.T) { msg := buildProto2("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, tc.uuid, 0, 0) err := msg.Validate() failed := err != nil if tc.fail != failed { t.Errorf("Expected validation failure: %t, but got %t, err: %v", tc.fail, failed, err) } }) t.Run(fmt.Sprintf("proto3 uuid '%s'", tc.uuid), func(t *testing.T) { msg := buildProto3("-%ab", 11, "abba", 99, 0.5, 0.5, 0.5, 0.5, "x", 4, "1234567890", stableBytes, uuid1, tc.uuid, 0, 0) err := msg.Validate() failed := err != nil if tc.fail != failed { t.Errorf("Expected validation failure: %t, but got %t, err: %v", tc.fail, failed, err) } }) } } golang-github-mwitkow-go-proto-validators-0.3.2/test/validator_proto2.proto000066400000000000000000000124301515653740400272240ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. syntax = "proto2"; package validatortest; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; import "github.com/mwitkow/go-proto-validators/validator.proto"; // Top-level enum type definition. enum EnumProto2 { alpha2 = 0; beta2 = 1; } message ValidatorMessage { // Embedded message test structure. message EmbeddedMessage { optional string Identifier = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}]; required int64 SomeValue = 2 [(validator.field) = {int_gt: 0, int_lt: 100}]; } // Embedded enum type definition. enum EmbeddedEnum { zero = 0; one = 1; } // String regex constraint tests. required string StringReq = 1 [(validator.field) = {regex: "^.{2,5}$"}]; required string StringReqNonNull = 2 [(validator.field) = {regex: "^.{2,5}$"}, (gogoproto.nullable) = false]; optional string StringOpt = 3 [(validator.field) = {regex: "^.{2,5}$"}]; optional string StringOptNonNull = 4 [(validator.field) = {regex: "^.{2,5}$"}, (gogoproto.nullable) = false]; required string StringUnescaped = 5 [(validator.field) = {regex: "[\\p{L}\\p{N}]({\\p{L}\\p{N}_- ]{0,28}[\\p{L}\\p{N}])?."}]; // Strict integer inequality constraint tests. required uint32 IntReq = 6 [(validator.field) = {int_gt: 10}]; required uint32 IntReqNonNull = 7 [(validator.field) = {int_gt: 0}, (gogoproto.nullable) = false]; repeated uint32 IntRep = 8 [(validator.field) = {int_gt: 10}]; repeated uint32 IntRepNonNull = 9 [(validator.field) = {int_gt: 0}]; // Embedded message recursive constraint tests. required EmbeddedMessage embeddedReq = 10; required EmbeddedMessage embeddedNonNull = 11 [(gogoproto.nullable) = false]; repeated EmbeddedMessage embeddedRep = 12; repeated EmbeddedMessage embeddedRepNonNullable = 13 [(gogoproto.nullable) = false]; // Custom error tests. optional int32 CustomErrorInt = 16 [(validator.field) = {int_gt: 10, human_error: "My Custom Error"}]; // Strict floating-point inequality constraint tests. // With this epsilon value, the limits become // SomeFloat+0.05 > 0.35 // SomeFloat-0.05 < 0.65 required double StrictSomeDoubleReq = 17 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; required double StrictSomeDoubleReqNonNull = 18 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}, (gogoproto.nullable) = false]; repeated double StrictSomeDoubleRep = 19 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; repeated double StrictSomeDoubleRepNonNull = 20 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; required float StrictSomeFloatReq = 21 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; required float StrictSomeFloatReqNonNull = 22 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}, (gogoproto.nullable) = false]; repeated float StrictSomeFloatRep = 23 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; repeated float StrictSomeFloatRepNonNull = 24 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; // Non-strict floating-point inequality constraint tests. required double SomeDoubleReq = 25 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; required double SomeDoubleReqNonNull = 26 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}, (gogoproto.nullable) = false]; repeated double SomeDoubleRep = 27 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; repeated double SomeDoubleRepNonNull = 28 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; required float SomeFloatReq = 29 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; required float SomeFloatReqNonNull = 30 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}, (gogoproto.nullable) = false]; repeated float SomeFloatRep = 31 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; repeated float SomeFloatRepNonNull = 32 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; // String not-empty constraint tests. required string SomeNonEmptyString = 33 [(validator.field) = {string_not_empty: true}]; // Repeated base-type without constraint tests. repeated int32 RepeatedBaseType = 34; // Repeated element count constraint tests. repeated int32 Repeated = 35 [(validator.field) = {repeated_count_min: 2, repeated_count_max: 5}]; optional string SomeStringLtReq = 36 [(validator.field) = {length_gt: 2}]; optional string SomeStringGtReq = 37 [(validator.field) = {length_lt: 12}]; optional string SomeStringEqReq = 38 [(validator.field) = {length_eq: 10}]; optional bytes SomeBytesLtReq = 39 [(validator.field) = {length_gt: 5}]; optional bytes SomeBytesGtReq = 40 [(validator.field) = {length_lt: 20}]; optional bytes SomeBytesEqReq = 41 [(validator.field) = {length_eq: 12}]; optional string UUIDAny = 42 [(validator.field) = {uuid_ver: 0}]; required string UUID4NotEmpty = 43 [(validator.field) = {uuid_ver: 4, string_not_empty: true}]; // Enum tests. required EnumProto2 someEnum = 44 [(validator.field) = {is_in_enum: true}]; required EmbeddedEnum someEmbeddedEnum = 45 [(validator.field) = {is_in_enum: true}]; // gogo embedded tests. required EmbeddedMessage someGogoEmbedded = 46 [(gogoproto.embed) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = ",inline"]; } golang-github-mwitkow-go-proto-validators-0.3.2/test/validator_proto3.proto000066400000000000000000000105641515653740400272330ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. syntax = "proto3"; package validatortest; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; import "github.com/mwitkow/go-proto-validators/validator.proto"; // Top-level enum type definition. enum EnumProto3 { alpha3 = 0; beta3 = 1; } message ValidatorMessage3 { // Embedded message test structure. message EmbeddedMessage { string Identifier = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}]; int64 SomeValue = 2 [(validator.field) = {int_gt: 0, int_lt: 100}]; } // Embedded enum type definition. enum EmbeddedEnum { zero = 0; one = 1; } // String regex constraint tests. string SomeString = 1 [(validator.field) = {regex: "^.{2,5}$"}]; repeated string SomeStringRep = 2 [(validator.field) = {regex: "^.{2,5}$"}]; string SomeStringNoQuotes = 3 [(validator.field) = {regex: "^[^\"]{2,5}$"}]; string SomeStringUnescaped = 4 [(validator.field) = {regex: "[\\p{L}\\p{N}]({\\p{L}\\p{N}_- ]{0,28}[\\p{L}\\p{N}])?."}]; // Strict integer inequality constraint tests. uint32 SomeInt = 6 [(validator.field) = {int_gt: 10}]; repeated uint32 SomeIntRep = 7 [(validator.field) = {int_gt: 10}]; repeated uint32 SomeIntRepNonNull = 8 [(validator.field) = {int_gt: 10}]; // Embedded message existence and recursive constraint tests. EmbeddedMessage someEmbedded = 10; EmbeddedMessage someEmbeddedNonNullable = 11 [(gogoproto.nullable) = false]; EmbeddedMessage someEmbeddedExists = 12 [(validator.field) = {msg_exists : true}]; repeated EmbeddedMessage someEmbeddedRep = 14; repeated EmbeddedMessage someEmbeddedRepNonNullable = 15 [(gogoproto.nullable) = false]; // Custom error tests. int32 CustomErrorInt = 16 [(validator.field) = {int_lt: 10, human_error: "My Custom Error"}]; // Strict floating-point inequality constraint tests. // With this epsilon value, the limits become // SomeFloat+0.05 > 0.35 // SomeFloat-0.05 < 0.65 double StrictSomeDouble = 17 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; repeated double StrictSomeDoubleRep = 19 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; repeated double StrictSomeDoubleRepNonNull = 20 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; float StrictSomeFloat = 21 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; repeated float StrictSomeFloatRep = 22 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; repeated float StrictSomeFloatRepNonNull = 23 [(validator.field) = {float_gt: 0.35, float_lt: 0.65, float_epsilon: 0.05}]; // Non-strict floating-point inequality constraint tests. double SomeDouble = 24 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; repeated double SomeDoubleRep = 25 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; repeated double SomeDoubleRepNonNull = 26 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; float SomeFloat = 27 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; repeated float SomeFloatRep = 28 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; repeated float SomeFloatRepNonNull = 30 [(validator.field) = {float_gte: 0.25, float_lte: 0.75}]; // String not-empty constraint tests. string SomeNonEmptyString = 31 [(validator.field) = {string_not_empty: true}]; // Repeated base-type without constraint tests. repeated int32 RepeatedBaseType = 32; // Repeated element count constraint tests. repeated int32 Repeated = 33 [(validator.field) = {repeated_count_min: 2, repeated_count_max: 5}]; string SomeStringLtReq = 36 [(validator.field) = {length_gt: 2}]; string SomeStringGtReq = 37 [(validator.field) = {length_lt: 12}]; string SomeStringEqReq = 38 [(validator.field) = {length_eq: 10}]; bytes SomeBytesLtReq = 39 [(validator.field) = {length_gt: 5}]; bytes SomeBytesGtReq = 40 [(validator.field) = {length_lt: 20}]; bytes SomeBytesEqReq = 41 [(validator.field) = {length_eq: 12}]; string UUIDAny = 42 [(validator.field) = {uuid_ver: 0}]; string UUID4NotEmpty = 43 [(validator.field) = {uuid_ver: 4, string_not_empty: true}]; // Enum tests. EnumProto3 someEnum = 44 [(validator.field) = {is_in_enum: true}]; EmbeddedEnum someEmbeddedEnum = 45 [(validator.field) = {is_in_enum: true}]; EmbeddedMessage someGogoEmbedded = 46 [(gogoproto.embed) = true, (gogoproto.nullable) = false, (gogoproto.jsontag) = ",inline"]; } golang-github-mwitkow-go-proto-validators-0.3.2/test/validator_proto3_map.proto000066400000000000000000000010141515653740400300560ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. syntax = "proto3"; package validatortest; message ValueType { string something = 1 ; } // This needs to be able to compile. Fixes https://github.com/mwitkow/go-proto-validators/issues/1 message ValidatorMapMessage3 { map SomeStringMap = 1; message NestedType { string something = 1 ; } map SomeExtMap = 2; map SomeNestedMap = 3; } golang-github-mwitkow-go-proto-validators-0.3.2/test/validator_proto3_oneof.proto000066400000000000000000000015721515653740400304200ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. syntax = "proto3"; package validatortest; import "github.com/mwitkow/go-proto-validators/validator.proto"; message ExternalMsg { string Identifier = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}]; int64 SomeValue = 2 [(validator.field) = {int_gt: 0, int_lt: 100}]; } message OneOfMessage3 { uint32 SomeInt = 1 [(validator.field) = {int_gt: 10}]; oneof type { ExternalMsg one_msg = 2; uint32 one_int = 3 [(validator.field) = {int_gt: 20}]; uint32 two_int = 4 [(validator.field) = {int_gt: 100}]; } oneof something { option (validator.oneof) = {required: true}; uint32 three_int = 5 [(validator.field) = {int_gt: 20}]; uint32 four_int = 6 [(validator.field) = {int_gt: 100}]; string five_regex = 7 [(validator.field) = {regex: "^[a-z]{2,5}$"}]; } } golang-github-mwitkow-go-proto-validators-0.3.2/validator.pb.go000066400000000000000000000312571515653740400246120ustar00rootroot00000000000000// Code generated by protoc-gen-gogo. DO NOT EDIT. // source: validator.proto package validator import ( fmt "fmt" proto "github.com/gogo/protobuf/proto" descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" math "math" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package type FieldValidator struct { // Uses a Golang RE2-syntax regex to match the field contents. Regex *string `protobuf:"bytes,1,opt,name=regex" json:"regex,omitempty"` // Field value of integer strictly greater than this value. IntGt *int64 `protobuf:"varint,2,opt,name=int_gt,json=intGt" json:"int_gt,omitempty"` // Field value of integer strictly smaller than this value. IntLt *int64 `protobuf:"varint,3,opt,name=int_lt,json=intLt" json:"int_lt,omitempty"` // Used for nested message types, requires that the message type exists. MsgExists *bool `protobuf:"varint,4,opt,name=msg_exists,json=msgExists" json:"msg_exists,omitempty"` // Human error specifies a user-customizable error that is visible to the user. HumanError *string `protobuf:"bytes,5,opt,name=human_error,json=humanError" json:"human_error,omitempty"` // Field value of double strictly greater than this value. // Note that this value can only take on a valid floating point // value. Use together with float_epsilon if you need something more specific. FloatGt *float64 `protobuf:"fixed64,6,opt,name=float_gt,json=floatGt" json:"float_gt,omitempty"` // Field value of double strictly smaller than this value. // Note that this value can only take on a valid floating point // value. Use together with float_epsilon if you need something more specific. FloatLt *float64 `protobuf:"fixed64,7,opt,name=float_lt,json=floatLt" json:"float_lt,omitempty"` // Field value of double describing the epsilon within which // any comparison should be considered to be true. For example, // when using float_gt = 0.35, using a float_epsilon of 0.05 // would mean that any value above 0.30 is acceptable. It can be // thought of as a {float_value_condition} +- {float_epsilon}. // If unset, no correction for floating point inaccuracies in // comparisons will be attempted. FloatEpsilon *float64 `protobuf:"fixed64,8,opt,name=float_epsilon,json=floatEpsilon" json:"float_epsilon,omitempty"` // Floating-point value compared to which the field content should be greater or equal. FloatGte *float64 `protobuf:"fixed64,9,opt,name=float_gte,json=floatGte" json:"float_gte,omitempty"` // Floating-point value compared to which the field content should be smaller or equal. FloatLte *float64 `protobuf:"fixed64,10,opt,name=float_lte,json=floatLte" json:"float_lte,omitempty"` // Used for string fields, requires the string to be not empty (i.e different from ""). StringNotEmpty *bool `protobuf:"varint,11,opt,name=string_not_empty,json=stringNotEmpty" json:"string_not_empty,omitempty"` // Repeated field with at least this number of elements. RepeatedCountMin *int64 `protobuf:"varint,12,opt,name=repeated_count_min,json=repeatedCountMin" json:"repeated_count_min,omitempty"` // Repeated field with at most this number of elements. RepeatedCountMax *int64 `protobuf:"varint,13,opt,name=repeated_count_max,json=repeatedCountMax" json:"repeated_count_max,omitempty"` // Field value of length greater than this value. LengthGt *int64 `protobuf:"varint,14,opt,name=length_gt,json=lengthGt" json:"length_gt,omitempty"` // Field value of length smaller than this value. LengthLt *int64 `protobuf:"varint,15,opt,name=length_lt,json=lengthLt" json:"length_lt,omitempty"` // Field value of integer strictly equal this value. LengthEq *int64 `protobuf:"varint,16,opt,name=length_eq,json=lengthEq" json:"length_eq,omitempty"` // Requires that the value is in the enum. IsInEnum *bool `protobuf:"varint,17,opt,name=is_in_enum,json=isInEnum" json:"is_in_enum,omitempty"` // Ensures that a string value is in UUID format. // uuid_ver specifies the valid UUID versions. Valid values are: 0-5. // If uuid_ver is 0 all UUID versions are accepted. UuidVer *int32 `protobuf:"varint,18,opt,name=uuid_ver,json=uuidVer" json:"uuid_ver,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *FieldValidator) Reset() { *m = FieldValidator{} } func (m *FieldValidator) String() string { return proto.CompactTextString(m) } func (*FieldValidator) ProtoMessage() {} func (*FieldValidator) Descriptor() ([]byte, []int) { return fileDescriptor_bf1c6ec7c0d80dd5, []int{0} } func (m *FieldValidator) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_FieldValidator.Unmarshal(m, b) } func (m *FieldValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_FieldValidator.Marshal(b, m, deterministic) } func (m *FieldValidator) XXX_Merge(src proto.Message) { xxx_messageInfo_FieldValidator.Merge(m, src) } func (m *FieldValidator) XXX_Size() int { return xxx_messageInfo_FieldValidator.Size(m) } func (m *FieldValidator) XXX_DiscardUnknown() { xxx_messageInfo_FieldValidator.DiscardUnknown(m) } var xxx_messageInfo_FieldValidator proto.InternalMessageInfo func (m *FieldValidator) GetRegex() string { if m != nil && m.Regex != nil { return *m.Regex } return "" } func (m *FieldValidator) GetIntGt() int64 { if m != nil && m.IntGt != nil { return *m.IntGt } return 0 } func (m *FieldValidator) GetIntLt() int64 { if m != nil && m.IntLt != nil { return *m.IntLt } return 0 } func (m *FieldValidator) GetMsgExists() bool { if m != nil && m.MsgExists != nil { return *m.MsgExists } return false } func (m *FieldValidator) GetHumanError() string { if m != nil && m.HumanError != nil { return *m.HumanError } return "" } func (m *FieldValidator) GetFloatGt() float64 { if m != nil && m.FloatGt != nil { return *m.FloatGt } return 0 } func (m *FieldValidator) GetFloatLt() float64 { if m != nil && m.FloatLt != nil { return *m.FloatLt } return 0 } func (m *FieldValidator) GetFloatEpsilon() float64 { if m != nil && m.FloatEpsilon != nil { return *m.FloatEpsilon } return 0 } func (m *FieldValidator) GetFloatGte() float64 { if m != nil && m.FloatGte != nil { return *m.FloatGte } return 0 } func (m *FieldValidator) GetFloatLte() float64 { if m != nil && m.FloatLte != nil { return *m.FloatLte } return 0 } func (m *FieldValidator) GetStringNotEmpty() bool { if m != nil && m.StringNotEmpty != nil { return *m.StringNotEmpty } return false } func (m *FieldValidator) GetRepeatedCountMin() int64 { if m != nil && m.RepeatedCountMin != nil { return *m.RepeatedCountMin } return 0 } func (m *FieldValidator) GetRepeatedCountMax() int64 { if m != nil && m.RepeatedCountMax != nil { return *m.RepeatedCountMax } return 0 } func (m *FieldValidator) GetLengthGt() int64 { if m != nil && m.LengthGt != nil { return *m.LengthGt } return 0 } func (m *FieldValidator) GetLengthLt() int64 { if m != nil && m.LengthLt != nil { return *m.LengthLt } return 0 } func (m *FieldValidator) GetLengthEq() int64 { if m != nil && m.LengthEq != nil { return *m.LengthEq } return 0 } func (m *FieldValidator) GetIsInEnum() bool { if m != nil && m.IsInEnum != nil { return *m.IsInEnum } return false } func (m *FieldValidator) GetUuidVer() int32 { if m != nil && m.UuidVer != nil { return *m.UuidVer } return 0 } type OneofValidator struct { // Require that one of the oneof fields is set. Required *bool `protobuf:"varint,1,opt,name=required" json:"required,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *OneofValidator) Reset() { *m = OneofValidator{} } func (m *OneofValidator) String() string { return proto.CompactTextString(m) } func (*OneofValidator) ProtoMessage() {} func (*OneofValidator) Descriptor() ([]byte, []int) { return fileDescriptor_bf1c6ec7c0d80dd5, []int{1} } func (m *OneofValidator) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OneofValidator.Unmarshal(m, b) } func (m *OneofValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OneofValidator.Marshal(b, m, deterministic) } func (m *OneofValidator) XXX_Merge(src proto.Message) { xxx_messageInfo_OneofValidator.Merge(m, src) } func (m *OneofValidator) XXX_Size() int { return xxx_messageInfo_OneofValidator.Size(m) } func (m *OneofValidator) XXX_DiscardUnknown() { xxx_messageInfo_OneofValidator.DiscardUnknown(m) } var xxx_messageInfo_OneofValidator proto.InternalMessageInfo func (m *OneofValidator) GetRequired() bool { if m != nil && m.Required != nil { return *m.Required } return false } var E_Field = &proto.ExtensionDesc{ ExtendedType: (*descriptor.FieldOptions)(nil), ExtensionType: (*FieldValidator)(nil), Field: 65020, Name: "validator.field", Tag: "bytes,65020,opt,name=field", Filename: "validator.proto", } var E_Oneof = &proto.ExtensionDesc{ ExtendedType: (*descriptor.OneofOptions)(nil), ExtensionType: (*OneofValidator)(nil), Field: 65021, Name: "validator.oneof", Tag: "bytes,65021,opt,name=oneof", Filename: "validator.proto", } func init() { proto.RegisterType((*FieldValidator)(nil), "validator.FieldValidator") proto.RegisterType((*OneofValidator)(nil), "validator.OneofValidator") proto.RegisterExtension(E_Field) proto.RegisterExtension(E_Oneof) } func init() { proto.RegisterFile("validator.proto", fileDescriptor_bf1c6ec7c0d80dd5) } var fileDescriptor_bf1c6ec7c0d80dd5 = []byte{ // 472 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x93, 0x41, 0x6f, 0xd4, 0x30, 0x10, 0x85, 0x15, 0xda, 0xb4, 0x89, 0xb7, 0xdd, 0x2e, 0x16, 0x48, 0x6e, 0xa1, 0x22, 0x2a, 0x97, 0x1c, 0xaa, 0x54, 0xe2, 0xc8, 0x11, 0x14, 0x56, 0x48, 0x0b, 0x45, 0x39, 0xf4, 0xc0, 0xc5, 0x0a, 0xcd, 0x6c, 0x6a, 0xc9, 0xb1, 0xb3, 0xf6, 0xa4, 0x5a, 0x7e, 0x1d, 0x3f, 0x0c, 0x90, 0x90, 0x1d, 0xb2, 0x49, 0xa5, 0x3d, 0xce, 0xfb, 0x26, 0x6f, 0xc6, 0xa3, 0x17, 0x72, 0xf6, 0x58, 0x4a, 0x51, 0x95, 0xa8, 0x4d, 0xd6, 0x1a, 0x8d, 0x9a, 0xc6, 0x3b, 0xe1, 0x22, 0xa9, 0xb5, 0xae, 0x25, 0xdc, 0x78, 0xf0, 0xa3, 0x5b, 0xdf, 0x54, 0x60, 0xef, 0x8d, 0x68, 0x77, 0xcd, 0x57, 0xbf, 0x0e, 0xc9, 0xfc, 0x93, 0x00, 0x59, 0xdd, 0x0d, 0x1f, 0xd1, 0x17, 0x24, 0x34, 0x50, 0xc3, 0x96, 0x05, 0x49, 0x90, 0xc6, 0x45, 0x5f, 0xd0, 0x97, 0xe4, 0x48, 0x28, 0xe4, 0x35, 0xb2, 0x67, 0x49, 0x90, 0x1e, 0x14, 0xa1, 0x50, 0xb8, 0xc4, 0x41, 0x96, 0xc8, 0x0e, 0x76, 0xf2, 0x0a, 0xe9, 0x25, 0x21, 0x8d, 0xad, 0x39, 0x6c, 0x85, 0x45, 0xcb, 0x0e, 0x93, 0x20, 0x8d, 0x8a, 0xb8, 0xb1, 0x75, 0xee, 0x05, 0xfa, 0x86, 0xcc, 0x1e, 0xba, 0xa6, 0x54, 0x1c, 0x8c, 0xd1, 0x86, 0x85, 0x7e, 0x10, 0xf1, 0x52, 0xee, 0x14, 0x7a, 0x4e, 0xa2, 0xb5, 0xd4, 0xa5, 0x9f, 0x77, 0x94, 0x04, 0x69, 0x50, 0x1c, 0xfb, 0x7a, 0x89, 0x23, 0x92, 0xc8, 0x8e, 0x27, 0x68, 0x85, 0xf4, 0x2d, 0x39, 0xed, 0x11, 0xb4, 0x56, 0x48, 0xad, 0x58, 0xe4, 0xf9, 0x89, 0x17, 0xf3, 0x5e, 0xa3, 0xaf, 0x48, 0x3c, 0x58, 0x03, 0x8b, 0x7d, 0x43, 0xf4, 0xdf, 0x1b, 0x46, 0x28, 0x11, 0x18, 0x99, 0xc0, 0x15, 0x02, 0x4d, 0xc9, 0xc2, 0xa2, 0x11, 0xaa, 0xe6, 0x4a, 0x23, 0x87, 0xa6, 0xc5, 0x9f, 0x6c, 0xe6, 0x9f, 0x36, 0xef, 0xf5, 0xaf, 0x1a, 0x73, 0xa7, 0xd2, 0x6b, 0x42, 0x0d, 0xb4, 0x50, 0x22, 0x54, 0xfc, 0x5e, 0x77, 0x0a, 0x79, 0x23, 0x14, 0x3b, 0xf1, 0x17, 0x5a, 0x0c, 0xe4, 0xa3, 0x03, 0x5f, 0x84, 0xda, 0xd7, 0x5d, 0x6e, 0xd9, 0xe9, 0xbe, 0xee, 0x72, 0xeb, 0x56, 0x94, 0xa0, 0x6a, 0x7c, 0x70, 0xb7, 0x99, 0xfb, 0xa6, 0xa8, 0x17, 0x96, 0x38, 0x81, 0x12, 0xd9, 0xd9, 0x14, 0xae, 0xa6, 0x10, 0x36, 0x6c, 0x31, 0x85, 0xf9, 0x86, 0xbe, 0x26, 0x44, 0x58, 0x2e, 0x14, 0x07, 0xd5, 0x35, 0xec, 0xb9, 0x7f, 0x56, 0x24, 0xec, 0x67, 0x95, 0xab, 0xae, 0x71, 0x47, 0xef, 0x3a, 0x51, 0xf1, 0x47, 0x30, 0x8c, 0x26, 0x41, 0x1a, 0x16, 0xc7, 0xae, 0xbe, 0x03, 0x73, 0x75, 0x4d, 0xe6, 0xb7, 0x0a, 0xf4, 0x7a, 0x0c, 0xd0, 0x05, 0x89, 0x0c, 0x6c, 0x3a, 0x61, 0xa0, 0xf2, 0x19, 0x8a, 0x8a, 0x5d, 0xfd, 0xfe, 0x1b, 0x09, 0xd7, 0x2e, 0x6e, 0xf4, 0x32, 0xeb, 0xb3, 0x99, 0x0d, 0xd9, 0xcc, 0x7c, 0x0c, 0x6f, 0x5b, 0x14, 0x5a, 0x59, 0xf6, 0xe7, 0xb7, 0xcb, 0xd3, 0xec, 0xdd, 0x79, 0x36, 0xc6, 0xfb, 0x69, 0x4e, 0x8b, 0xde, 0xc8, 0x39, 0x6a, 0x37, 0x7f, 0x8f, 0xa3, 0xdf, 0x6b, 0x70, 0xfc, 0xbb, 0xc7, 0xf1, 0xe9, 0xe2, 0x45, 0x6f, 0xf4, 0x61, 0xf6, 0x7d, 0xfc, 0x85, 0xfe, 0x05, 0x00, 0x00, 0xff, 0xff, 0x05, 0x20, 0x26, 0x13, 0x5f, 0x03, 0x00, 0x00, } golang-github-mwitkow-go-proto-validators-0.3.2/validator.proto000066400000000000000000000064031515653740400247430ustar00rootroot00000000000000// Copyright 2016 Michal Witkowski. All Rights Reserved. // See LICENSE for licensing terms. // Protocol Buffers extensions for defining auto-generateable validators for messages. // TODO(mwitkow): Add example. syntax = "proto2"; package validator; import "google/protobuf/descriptor.proto"; option go_package = "github.com/mwitkow/go-proto-validators;validator"; // TODO(mwitkow): Email protobuf-global-extension-registry@google.com to get an extension ID. extend google.protobuf.FieldOptions { optional FieldValidator field = 65020; } extend google.protobuf.OneofOptions { optional OneofValidator oneof = 65021; } message FieldValidator { // Uses a Golang RE2-syntax regex to match the field contents. optional string regex = 1; // Field value of integer strictly greater than this value. optional int64 int_gt = 2; // Field value of integer strictly smaller than this value. optional int64 int_lt = 3; // Used for nested message types, requires that the message type exists. optional bool msg_exists = 4; // Human error specifies a user-customizable error that is visible to the user. optional string human_error = 5; // Field value of double strictly greater than this value. // Note that this value can only take on a valid floating point // value. Use together with float_epsilon if you need something more specific. optional double float_gt = 6; // Field value of double strictly smaller than this value. // Note that this value can only take on a valid floating point // value. Use together with float_epsilon if you need something more specific. optional double float_lt = 7; // Field value of double describing the epsilon within which // any comparison should be considered to be true. For example, // when using float_gt = 0.35, using a float_epsilon of 0.05 // would mean that any value above 0.30 is acceptable. It can be // thought of as a {float_value_condition} +- {float_epsilon}. // If unset, no correction for floating point inaccuracies in // comparisons will be attempted. optional double float_epsilon = 8; // Floating-point value compared to which the field content should be greater or equal. optional double float_gte = 9; // Floating-point value compared to which the field content should be smaller or equal. optional double float_lte = 10; // Used for string fields, requires the string to be not empty (i.e different from ""). optional bool string_not_empty = 11; // Repeated field with at least this number of elements. optional int64 repeated_count_min = 12; // Repeated field with at most this number of elements. optional int64 repeated_count_max = 13; // Field value of length greater than this value. optional int64 length_gt = 14; // Field value of length smaller than this value. optional int64 length_lt = 15; // Field value of length strictly equal to this value. optional int64 length_eq = 16; // Requires that the value is in the enum. optional bool is_in_enum = 17; // Ensures that a string value is in UUID format. // uuid_ver specifies the valid UUID versions. Valid values are: 0-5. // If uuid_ver is 0 all UUID versions are accepted. optional int32 uuid_ver = 18; } message OneofValidator { // Require that one of the oneof fields is set. optional bool required = 1; }