binding/common_test.go
KN4CK3R 1d3a5e518f
All checks were successful
test / check and test (push) Successful in 19m34s
Add support for non-struct pointers (#5)
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>
2024-03-08 08:14:13 +00:00

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"
)