KN4CK3R
1d3a5e518f
All checks were successful
test / check and test (push) Successful in 19m34s
This PR adds support for pointers to optional fields in forms. This example fails in the old version: ```go type TestForm struct { Test string `binding:"Url"` TestPtr *string `binding:"Url"` } empty := "" form := &TestForm{ Test: "", TestPtr: &empty, } _ := RawValidate(form) ``` The empty `Test` field is no problem because an empty field is valid url. The empty pointer field throws an error because the regex checks against the wrong field value of `"0xc000011dc0"`. So the memory address is formatted as string and tested. After the change both fields pass because both are treated equal. Fixes the workaround in https://github.com/go-gitea/gitea/pull/15690 Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: #5 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: KN4CK3R <admin@oldschoolhack.me> Co-committed-by: KN4CK3R <admin@oldschoolhack.me>
132 lines
4.3 KiB
Go
Executable File
132 lines
4.3 KiB
Go
Executable File
// Copyright 2014 Martini Authors
|
|
// Copyright 2014 The Macaron Authors
|
|
//
|
|
// 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.
|
|
|
|
package binding
|
|
|
|
import (
|
|
"mime/multipart"
|
|
"net/http"
|
|
)
|
|
|
|
// These types are mostly contrived examples, but they're used
|
|
// across many test cases. The idea is to cover all the scenarios
|
|
// that this binding package might encounter in actual use.
|
|
type (
|
|
// For basic test cases with a required field
|
|
Post struct {
|
|
Title string `form:"title" json:"title" binding:"Required"`
|
|
Content string `form:"content" json:"content"`
|
|
}
|
|
|
|
// To be used as a nested struct (with a required field)
|
|
Person struct {
|
|
Name string `form:"name" json:"name" binding:"Required"`
|
|
Email string `form:"email" json:"email"`
|
|
}
|
|
|
|
// For advanced test cases: multiple values, embedded
|
|
// and nested structs, an ignored field, and single
|
|
// and multiple file uploads
|
|
BlogPost struct {
|
|
Post
|
|
Id int `binding:"Required"` // JSON not specified here for test coverage
|
|
Ignored string `form:"-" json:"-"`
|
|
Ratings []int `form:"rating" json:"ratings"`
|
|
Author Person `json:"author"`
|
|
Coauthor *Person `json:"coauthor"`
|
|
HeaderImage *multipart.FileHeader
|
|
Pictures []*multipart.FileHeader `form:"picture"`
|
|
unexported string `form:"unexported"`
|
|
}
|
|
|
|
EmbedPerson struct {
|
|
*Person
|
|
}
|
|
|
|
SadForm struct {
|
|
AlphaDash string `form:"AlphaDash" binding:"AlphaDash"`
|
|
AlphaDashDot string `form:"AlphaDashDot" binding:"AlphaDashDot"`
|
|
Size string `form:"Size" binding:"Size(1)"`
|
|
SizeSlice []string `form:"SizeSlice" binding:"Size(1)"`
|
|
MinSize string `form:"MinSize" binding:"MinSize(5)"`
|
|
MinSizeSlice []string `form:"MinSizeSlice" binding:"MinSize(5)"`
|
|
MaxSize string `form:"MaxSize" binding:"MaxSize(1)"`
|
|
MaxSizeSlice []string `form:"MaxSizeSlice" binding:"MaxSize(1)"`
|
|
Range int `form:"Range" binding:"Range(1,2)"`
|
|
RangeInvalid int `form:"RangeInvalid" binding:"Range(1)"`
|
|
Email string `binding:"Email"`
|
|
Url string `form:"Url" binding:"Url"`
|
|
UrlEmpty string `form:"UrlEmpty" binding:"Url"`
|
|
In string `form:"In" binding:"Default(0);In(1,2,3)"`
|
|
InInvalid string `form:"InInvalid" binding:"In(1,2,3)"`
|
|
NotIn string `form:"NotIn" binding:"NotIn(1,2,3)"`
|
|
Include string `form:"Include" binding:"Include(a)"`
|
|
Exclude string `form:"Exclude" binding:"Exclude(a)"`
|
|
Empty string
|
|
}
|
|
|
|
Group struct {
|
|
Name string `json:"name" binding:"Required"`
|
|
People []Person `json:"people" binding:"MinSize(1)"`
|
|
}
|
|
|
|
PointerForm struct {
|
|
Url string `form:"Url" binding:"Url"`
|
|
UrlPointer *string `form:"UrlPointer" binding:"Url"`
|
|
AlphaDash string `form:"AlphaDash" binding:"AlphaDash"`
|
|
AlphaDashPointer *string `form:"AlphaDashPointer" binding:"AlphaDash"`
|
|
}
|
|
|
|
CustomErrorHandle struct {
|
|
Rule `binding:"CustomRule"`
|
|
}
|
|
|
|
// The common function signature of the handlers going under test.
|
|
handlerFunc func(req *http.Request, obj interface{}) Errors
|
|
|
|
// Used for testing mapping an interface to the context
|
|
// If used (withInterface = true in the testCases), a modeler
|
|
// should be mapped to the context as well as BlogPost, meaning
|
|
// you can receive a modeler in your application instead of a
|
|
// concrete BlogPost.
|
|
modeler interface {
|
|
Model() string
|
|
}
|
|
)
|
|
|
|
func (p Post) Validate(req *http.Request, errs Errors) Errors {
|
|
if len(p.Title) < 10 {
|
|
errs = append(errs, Error{
|
|
FieldNames: []string{"title"},
|
|
Classification: "LengthError",
|
|
Message: "Life is too short",
|
|
})
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func (p Post) Model() string {
|
|
return p.Title
|
|
}
|
|
|
|
func (g Group) Model() string {
|
|
return g.Name
|
|
}
|
|
|
|
const (
|
|
testRoute = "/test"
|
|
formContentType = "application/x-www-form-urlencoded"
|
|
)
|