Adding upstream version 1.0.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
5ca5eb8df5
commit
4a5c02e4d1
19 changed files with 3254 additions and 0 deletions
269
json_test.go
Executable file
269
json_test.go
Executable file
|
@ -0,0 +1,269 @@
|
|||
// Copyright 2014 Martini Authors
|
||||
// Copyright 2014 The Macaron Authors
|
||||
// Copyright 2024 The Forgejo 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 (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
chi "github.com/go-chi/chi/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var jsonTestCases = []jsonTestCase{
|
||||
{
|
||||
description: "Happy path",
|
||||
shouldSucceedOnJSON: true,
|
||||
payload: `{"title": "Glorious Post Title", "content": "Lorem ipsum dolor sit amet"}`,
|
||||
contentType: jsonContentType,
|
||||
expected: Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
|
||||
},
|
||||
{
|
||||
description: "Happy path with interface",
|
||||
shouldSucceedOnJSON: true,
|
||||
withInterface: true,
|
||||
payload: `{"title": "Glorious Post Title", "content": "Lorem ipsum dolor sit amet"}`,
|
||||
contentType: jsonContentType,
|
||||
expected: Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
|
||||
},
|
||||
{
|
||||
description: "Nil payload",
|
||||
shouldSucceedOnJSON: false,
|
||||
payload: `-nil-`,
|
||||
contentType: jsonContentType,
|
||||
expected: Post{},
|
||||
},
|
||||
{
|
||||
description: "Empty payload",
|
||||
shouldSucceedOnJSON: false,
|
||||
payload: ``,
|
||||
contentType: jsonContentType,
|
||||
expected: Post{},
|
||||
},
|
||||
{
|
||||
description: "Empty content type",
|
||||
shouldSucceedOnJSON: true,
|
||||
shouldFailOnBind: true,
|
||||
payload: `{"title": "Glorious Post Title", "content": "Lorem ipsum dolor sit amet"}`,
|
||||
contentType: ``,
|
||||
expected: Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
|
||||
},
|
||||
{
|
||||
description: "Unsupported content type",
|
||||
shouldSucceedOnJSON: true,
|
||||
shouldFailOnBind: true,
|
||||
payload: `{"title": "Glorious Post Title", "content": "Lorem ipsum dolor sit amet"}`,
|
||||
contentType: `BoGuS`,
|
||||
expected: Post{Title: "Glorious Post Title", Content: "Lorem ipsum dolor sit amet"},
|
||||
},
|
||||
{
|
||||
description: "Malformed JSON",
|
||||
shouldSucceedOnJSON: false,
|
||||
payload: `{"title":"foo"`,
|
||||
contentType: jsonContentType,
|
||||
expected: Post{Title: "foo"},
|
||||
},
|
||||
{
|
||||
description: "Deserialization with nested and embedded struct",
|
||||
shouldSucceedOnJSON: true,
|
||||
payload: `{"title":"Glorious Post Title", "id":1, "author":{"name":"Matt Holt"}}`,
|
||||
contentType: jsonContentType,
|
||||
expected: BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1, Author: Person{Name: "Matt Holt"}},
|
||||
},
|
||||
{
|
||||
description: "Deserialization with nested and embedded struct with interface",
|
||||
shouldSucceedOnJSON: true,
|
||||
withInterface: true,
|
||||
payload: `{"title":"Glorious Post Title", "id":1, "author":{"name":"Matt Holt"}}`,
|
||||
contentType: jsonContentType,
|
||||
expected: BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1, Author: Person{Name: "Matt Holt"}},
|
||||
},
|
||||
{
|
||||
description: "Required nested struct field not specified",
|
||||
shouldSucceedOnJSON: false,
|
||||
payload: `{"title":"Glorious Post Title", "id":1, "author":{}}`,
|
||||
contentType: jsonContentType,
|
||||
expected: BlogPost{Post: Post{Title: "Glorious Post Title"}, Id: 1},
|
||||
},
|
||||
{
|
||||
description: "Required embedded struct field not specified",
|
||||
shouldSucceedOnJSON: false,
|
||||
payload: `{"id":1, "author":{"name":"Matt Holt"}}`,
|
||||
contentType: jsonContentType,
|
||||
expected: BlogPost{Id: 1, Author: Person{Name: "Matt Holt"}},
|
||||
},
|
||||
{
|
||||
description: "Slice of Posts",
|
||||
shouldSucceedOnJSON: true,
|
||||
payload: `[{"title": "First Post"}, {"title": "Second Post"}]`,
|
||||
contentType: jsonContentType,
|
||||
expected: []Post{{Title: "First Post"}, {Title: "Second Post"}},
|
||||
},
|
||||
{
|
||||
description: "Slice of structs",
|
||||
shouldSucceedOnJSON: true,
|
||||
payload: `{"name": "group1", "people": [{"name":"awoods"}, {"name": "anthony"}]}`,
|
||||
contentType: jsonContentType,
|
||||
expected: Group{Name: "group1", People: []Person{{Name: "awoods"}, {Name: "anthony"}}},
|
||||
},
|
||||
}
|
||||
|
||||
func Test_Json(t *testing.T) {
|
||||
for _, testCase := range jsonTestCases {
|
||||
performJSONTest(t, JSON, testCase)
|
||||
}
|
||||
}
|
||||
|
||||
func performJSONTest(t *testing.T, binder handlerFunc, testCase jsonTestCase) {
|
||||
fnName := runtime.FuncForPC(reflect.ValueOf(binder).Pointer()).Name()
|
||||
t.Run(testCase.description, func(t *testing.T) {
|
||||
var payload io.Reader
|
||||
httpRecorder := httptest.NewRecorder()
|
||||
m := chi.NewRouter()
|
||||
|
||||
jsonTestHandler := func(actual any, errs Errors) {
|
||||
switch fnName {
|
||||
case "JSON":
|
||||
if testCase.shouldSucceedOnJSON {
|
||||
assert.Empty(t, errs, errs)
|
||||
assert.EqualValues(t, fmt.Sprintf("%+v", testCase.expected), fmt.Sprintf("%+v", actual))
|
||||
} else {
|
||||
assert.NotEmpty(t, errs)
|
||||
}
|
||||
case "Bind":
|
||||
if !testCase.shouldFailOnBind {
|
||||
assert.Empty(t, errs, errs)
|
||||
} else {
|
||||
assert.NotEmpty(t, errs)
|
||||
assert.EqualValues(t, fmt.Sprintf("%+v", testCase.expected), fmt.Sprintf("%+v", actual))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch p := testCase.expected.(type) {
|
||||
case []Post:
|
||||
if testCase.withInterface {
|
||||
m.Post(testRoute, func(_ http.ResponseWriter, req *http.Request) {
|
||||
var actual []Post
|
||||
errs := binder(req, &actual)
|
||||
for i, a := range actual {
|
||||
assert.EqualValues(t, p[i].Title, a.Title)
|
||||
jsonTestHandler(a, errs)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
m.Post(testRoute, func(_ http.ResponseWriter, req *http.Request) {
|
||||
var actual []Post
|
||||
errs := binder(req, &actual)
|
||||
jsonTestHandler(actual, errs)
|
||||
})
|
||||
}
|
||||
|
||||
case Post:
|
||||
if testCase.withInterface {
|
||||
m.Post(testRoute, func(_ http.ResponseWriter, req *http.Request) {
|
||||
var actual Post
|
||||
errs := binder(req, &actual)
|
||||
assert.EqualValues(t, p.Title, actual.Title)
|
||||
jsonTestHandler(actual, errs)
|
||||
})
|
||||
} else {
|
||||
m.Post(testRoute, func(_ http.ResponseWriter, req *http.Request) {
|
||||
var actual Post
|
||||
errs := binder(req, &actual)
|
||||
jsonTestHandler(actual, errs)
|
||||
})
|
||||
}
|
||||
|
||||
case BlogPost:
|
||||
if testCase.withInterface {
|
||||
m.Post(testRoute, func(_ http.ResponseWriter, req *http.Request) {
|
||||
var actual BlogPost
|
||||
errs := binder(req, &actual)
|
||||
assert.EqualValues(t, p.Title, actual.Title)
|
||||
jsonTestHandler(actual, errs)
|
||||
})
|
||||
} else {
|
||||
m.Post(testRoute, func(_ http.ResponseWriter, req *http.Request) {
|
||||
var actual BlogPost
|
||||
errs := binder(req, &actual)
|
||||
jsonTestHandler(actual, errs)
|
||||
})
|
||||
}
|
||||
case Group:
|
||||
if testCase.withInterface {
|
||||
m.Post(testRoute, func(_ http.ResponseWriter, req *http.Request) {
|
||||
var actual Group
|
||||
errs := binder(req, &actual)
|
||||
assert.EqualValues(t, p.Name, actual.Name)
|
||||
jsonTestHandler(actual, errs)
|
||||
})
|
||||
} else {
|
||||
m.Post(testRoute, func(_ http.ResponseWriter, req *http.Request) {
|
||||
var actual Group
|
||||
errs := binder(req, &actual)
|
||||
jsonTestHandler(actual, errs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if testCase.payload == "-nil-" {
|
||||
payload = nil
|
||||
} else {
|
||||
payload = strings.NewReader(testCase.payload)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", testRoute, payload)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
req.Header.Set("Content-Type", testCase.contentType)
|
||||
|
||||
m.ServeHTTP(httpRecorder, req)
|
||||
|
||||
switch httpRecorder.Code {
|
||||
case http.StatusNotFound:
|
||||
panic("Routing is messed up in test fixture (got 404): check method and path")
|
||||
case http.StatusInternalServerError:
|
||||
panic("Something bad happened on '" + testCase.description + "'")
|
||||
default:
|
||||
if testCase.shouldSucceedOnJSON &&
|
||||
httpRecorder.Code != http.StatusOK &&
|
||||
!testCase.shouldFailOnBind {
|
||||
assert.EqualValues(t, http.StatusOK, httpRecorder.Code)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type (
|
||||
jsonTestCase struct {
|
||||
description string
|
||||
withInterface bool
|
||||
shouldSucceedOnJSON bool
|
||||
shouldFailOnBind bool
|
||||
payload string
|
||||
contentType string
|
||||
expected any
|
||||
}
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue