Files
gf/net/ghttp/ghttp_z_unit_feature_request_struct_test.go
hailaz ee24da4e72 refactor: interface{} to any and reflect.Ptr to reflect.Pointer (#4395)
This pull request standardizes the use of the Go 1.18+ `any` type alias
instead of `interface{}` throughout the codebase. The change improves
code readability and aligns with modern Go best practices. The update
touches many files, including core data structures, code generation
templates, logging utilities, and test data, ensuring consistency across
all usages.

**Type alias migration to `any`:**

* Replaced all instances of `interface{}` with `any` in core data
structures such as `garray` and in generated model structs (e.g.,
`TableUser`, `User1`, `User2`) to modernize type usage.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
* Updated function signatures, method parameters, and return types from
`interface{}` to `any` in various parts of the codebase, including code
generation, service logic, and logging utilities (e.g., `mlog`).
[[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74)
[[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
[[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107)
[[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121)
[[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112)
[[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36)
[[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74)
[[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96)

**Generated code and templates:**

* Adjusted generated files and code generation templates to output `any`
instead of `interface{}` for relevant struct fields and function
signatures, ensuring that new code generation aligns with the updated
convention.
[[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
[[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)

**Container and utility updates:**

* Refactored the `garray` container implementation and related
constructors/methods to use `[]any` instead of `[]interface{}`, along
with corresponding function signatures.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52)
[[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62)
[[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86)
[[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97)
[[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114)
[[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124)
[[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143)
[[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167)

These changes collectively modernize the codebase and prepare it for
future Go developments by using the idiomatic `any` type.
2025-08-28 16:53:19 +08:00

597 lines
16 KiB
Go

// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package ghttp_test
import (
"fmt"
"testing"
"time"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/util/guid"
"github.com/gogf/gf/v2/util/gvalid"
)
func Test_Params_Parse(t *testing.T) {
type User struct {
Id int
Name string
Map map[string]any
}
s := g.Server(guid.S())
s.BindHandler("/parse", func(r *ghttp.Request) {
var user *User
if err := r.Parse(&user); err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(user.Map["id"], user.Map["score"])
})
s.BindHandler("/parseErr", func(r *ghttp.Request) {
var user User
err := r.Parse(user)
r.Response.WriteExit(err != nil)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(client.PostContent(ctx, "/parse", `{"id":1,"name":"john","map":{"id":1,"score":100}}`), `1100`)
t.Assert(client.PostContent(ctx, "/parseErr", `{"id":1,"name":"john","map":{"id":1,"score":100}}`), true)
})
}
func Test_Params_ParseQuery(t *testing.T) {
type User struct {
Id int
Name string
}
s := g.Server(guid.S())
s.BindHandler("/parse-query", func(r *ghttp.Request) {
var user *User
if err := r.ParseQuery(&user); err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(user.Id, user.Name)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
c := g.Client()
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(c.GetContent(ctx, "/parse-query"), `0`)
t.Assert(c.GetContent(ctx, "/parse-query?id=1&name=john"), `1john`)
t.Assert(c.PostContent(ctx, "/parse-query"), `0`)
t.Assert(c.PostContent(ctx, "/parse-query", g.Map{
"id": 1,
"name": "john",
}), `0`)
})
}
func Test_Params_ParseForm(t *testing.T) {
type User struct {
Id int
Name string
}
s := g.Server(guid.S())
s.BindHandler("/parse-form", func(r *ghttp.Request) {
var user *User
if err := r.ParseForm(&user); err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(user.Id, user.Name)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
c := g.Client()
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(c.GetContent(ctx, "/parse-form"), `0`)
t.Assert(c.GetContent(ctx, "/parse-form", g.Map{
"id": 1,
"name": "john",
}), 0)
t.Assert(c.PostContent(ctx, "/parse-form"), `0`)
t.Assert(c.PostContent(ctx, "/parse-form", g.Map{
"id": 1,
"name": "john",
}), `1john`)
})
}
// https://github.com/gogf/gf/pull/4143
func Test_Params_ParseForm_FixMakeBodyRepeatableRead(t *testing.T) {
type User struct {
Id int
Name string
}
s := g.Server(guid.S())
s.BindHandler("/parse-form", func(r *ghttp.Request) {
var user *User
if err := r.ParseForm(&user); err != nil {
r.Response.WriteExit(err)
}
hasBody := len(r.GetBody()) > 0
r.Response.WriteExit(hasBody)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
c := g.Client()
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(c.GetContent(ctx, "/parse-form"), `false`)
t.Assert(c.GetContent(ctx, "/parse-form", g.Map{
"id": 1,
"name": "john",
}), false)
t.Assert(c.PostContent(ctx, "/parse-form"), `false`)
t.Assert(c.PostContent(ctx, "/parse-form", g.Map{
"id": 1,
"name": "john",
}), true)
})
}
func Test_Params_ComplexJsonStruct(t *testing.T) {
type ItemEnv struct {
Type string
Key string
Value string
Brief string
}
type ItemProbe struct {
Type string
Port int
Path string
Brief string
Period int
InitialDelay int
TimeoutSeconds int
}
type ItemKV struct {
Key string
Value string
}
type ItemPort struct {
Port int
Type string
Alias string
Brief string
}
type ItemMount struct {
Type string
DstPath string
Src string
SrcPath string
Brief string
}
type SaveRequest struct {
AppId uint
Name string
Type string
Cluster string
Replicas uint
ContainerName string
ContainerImage string
VersionTag string
Namespace string
Id uint
Status uint
Metrics string
InitImage string
CpuRequest uint
CpuLimit uint
MemRequest uint
MemLimit uint
MeshEnabled uint
ContainerPorts []ItemPort
Labels []ItemKV
NodeSelector []ItemKV
EnvReserve []ItemKV
EnvGlobal []ItemEnv
EnvContainer []ItemEnv
Mounts []ItemMount
LivenessProbe ItemProbe
ReadinessProbe ItemProbe
}
s := g.Server(guid.S())
s.BindHandler("/parse", func(r *ghttp.Request) {
if m := r.GetMap(); len(m) > 0 {
var data *SaveRequest
if err := r.Parse(&data); err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(data)
}
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
content := `
{
"app_id": 5,
"cluster": "test",
"container_image": "nginx",
"container_name": "test",
"container_ports": [
{
"alias": "别名",
"brief": "描述",
"port": 80,
"type": "tcp"
}
],
"cpu_limit": 100,
"cpu_request": 10,
"create_at": "2020-10-10 12:00:00",
"creator": 1,
"env_container": [
{
"brief": "用户环境变量",
"key": "NAME",
"type": "string",
"value": "john"
}
],
"env_global": [
{
"brief": "数据数量",
"key": "NUMBER",
"type": "string",
"value": "1"
}
],
"env_reserve": [
{
"key": "NODE_IP",
"value": "status.hostIP"
}
],
"liveness_probe": {
"brief": "存活探针",
"initial_delay": 10,
"path": "",
"period": 5,
"port": 80,
"type": "tcpSocket"
},
"readiness_probe": {
"brief": "就绪探针",
"initial_delay": 10,
"path": "",
"period": 5,
"port": 80,
"type": "tcpSocket"
},
"id": 0,
"init_image": "",
"labels": [
{
"key": "app",
"value": "test"
}
],
"mem_limit": 1000,
"mem_request": 100,
"mesh_enabled": 0,
"metrics": "",
"mounts": [],
"name": "test",
"namespace": "test",
"node_selector": [
{
"key": "group",
"value": "app"
}
],
"replicas": 1,
"type": "test",
"update_at": "2020-10-10 12:00:00",
"version_tag": "test"
}
`
t.Assert(client.PostContent(ctx, "/parse", content), `{"AppId":5,"Name":"test","Type":"test","Cluster":"test","Replicas":1,"ContainerName":"test","ContainerImage":"nginx","VersionTag":"test","Namespace":"test","Id":0,"Status":0,"Metrics":"","InitImage":"","CpuRequest":10,"CpuLimit":100,"MemRequest":100,"MemLimit":1000,"MeshEnabled":0,"ContainerPorts":[{"Port":80,"Type":"tcp","Alias":"别名","Brief":"描述"}],"Labels":[{"Key":"app","Value":"test"}],"NodeSelector":[{"Key":"group","Value":"app"}],"EnvReserve":[{"Key":"NODE_IP","Value":"status.hostIP"}],"EnvGlobal":[{"Type":"string","Key":"NUMBER","Value":"1","Brief":"数据数量"}],"EnvContainer":[{"Type":"string","Key":"NAME","Value":"john","Brief":"用户环境变量"}],"Mounts":[],"LivenessProbe":{"Type":"tcpSocket","Port":80,"Path":"","Brief":"存活探针","Period":5,"InitialDelay":10,"TimeoutSeconds":0},"ReadinessProbe":{"Type":"tcpSocket","Port":80,"Path":"","Brief":"就绪探针","Period":5,"InitialDelay":10,"TimeoutSeconds":0}}`)
})
}
func Test_Params_Parse_Attr_Pointer1(t *testing.T) {
type User struct {
Id *int
Name *string
}
s := g.Server(guid.S())
s.BindHandler("/parse1", func(r *ghttp.Request) {
if m := r.GetMap(); len(m) > 0 {
var user *User
if err := r.Parse(&user); err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(user.Id, user.Name)
}
})
s.BindHandler("/parse2", func(r *ghttp.Request) {
if m := r.GetMap(); len(m) > 0 {
var user = new(User)
if err := r.Parse(user); err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(user.Id, user.Name)
}
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(client.PostContent(ctx, "/parse1", `{"id":1,"name":"john"}`), `1john`)
t.Assert(client.PostContent(ctx, "/parse2", `{"id":1,"name":"john"}`), `1john`)
t.Assert(client.PostContent(ctx, "/parse2?id=1&name=john"), `1john`)
t.Assert(client.PostContent(ctx, "/parse2", `id=1&name=john`), `1john`)
})
}
func Test_Params_Parse_Attr_Pointer2(t *testing.T) {
type User struct {
Id *int `v:"required"`
}
s := g.Server(guid.S())
s.BindHandler("/parse", func(r *ghttp.Request) {
var user *User
if err := r.Parse(&user); err != nil {
r.Response.WriteExit(err.Error())
}
r.Response.WriteExit(user.Id)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(client.PostContent(ctx, "/parse"), `The Id field is required`)
t.Assert(client.PostContent(ctx, "/parse?id=1"), `1`)
})
}
// It does not support this kind of converting yet.
// func Test_Params_Parse_Attr_SliceSlice(t *testing.T) {
// type User struct {
// Id int
// Name string
// Scores [][]int
// }
// // s := g.Server(guid.S())
// s.BindHandler("/parse", func(r *ghttp.Request) {
// if m := r.GetMap(); len(m) > 0 {
// var user *User
// if err := r.Parse(&user); err != nil {
// r.Response.WriteExit(err)
// }
// r.Response.WriteExit(user.Scores)
// }
// })
// // s.SetDumpRouterMap(false)
// s.Start()
// defer s.Shutdown()
//
// time.Sleep(100 * time.Millisecond)
// gtest.C(t, func(t *gtest.T) {
// client := g.Client()
// client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
// t.Assert(client.PostContent(ctx, "/parse", `{"id":1,"name":"john","scores":[[1,2,3]]}`), `1100`)
// })
// }
func Test_Params_Struct(t *testing.T) {
type User struct {
Id int
Name string
Time *time.Time
Pass1 string `p:"password1"`
Pass2 string `p:"password2" v:"password2 @required|length:2,20|password3#||密码强度不足"`
}
s := g.Server(guid.S())
s.BindHandler("/struct1", func(r *ghttp.Request) {
if m := r.GetMap(); len(m) > 0 {
user := new(User)
if err := r.GetStruct(user); err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(user.Id, user.Name, user.Pass1, user.Pass2)
}
})
s.BindHandler("/struct2", func(r *ghttp.Request) {
if m := r.GetMap(); len(m) > 0 {
user := (*User)(nil)
if err := r.GetStruct(&user); err != nil {
r.Response.WriteExit(err)
}
if user != nil {
r.Response.WriteExit(user.Id, user.Name, user.Pass1, user.Pass2)
}
}
})
s.BindHandler("/struct-valid", func(r *ghttp.Request) {
if m := r.GetMap(); len(m) > 0 {
user := new(User)
if err := r.GetStruct(user); err != nil {
r.Response.WriteExit(err)
}
if err := gvalid.New().Data(user).Run(r.Context()); err != nil {
r.Response.WriteExit(err)
}
}
})
s.BindHandler("/parse", func(r *ghttp.Request) {
if m := r.GetMap(); len(m) > 0 {
var user *User
if err := r.Parse(&user); err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(user.Id, user.Name, user.Pass1, user.Pass2)
}
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(client.GetContent(ctx, "/struct1", `id=1&name=john&password1=123&password2=456`), `1john123456`)
t.Assert(client.PostContent(ctx, "/struct1", `id=1&name=john&password1=123&password2=456`), `1john123456`)
t.Assert(client.PostContent(ctx, "/struct2", `id=1&name=john&password1=123&password2=456`), `1john123456`)
t.Assert(client.PostContent(ctx, "/struct2", ``), ``)
t.Assert(client.PostContent(ctx, "/struct-valid", `id=1&name=john&password1=123&password2=0`), "The password2 value `0` length must be between 2 and 20; 密码强度不足")
t.Assert(client.PostContent(ctx, "/parse", `id=1&name=john&password1=123&password2=0`), "The password2 value `0` length must be between 2 and 20")
t.Assert(client.PostContent(ctx, "/parse", `{"id":1,"name":"john","password1":"123Abc!@#","password2":"123Abc!@#"}`), `1john123Abc!@#123Abc!@#`)
})
}
func Test_Params_Structs(t *testing.T) {
type User struct {
Id int
Name string
Time *time.Time
Pass1 string `p:"password1"`
Pass2 string `p:"password2" v:"password2 @required|length:2,20|password3#||密码强度不足"`
}
s := g.Server(guid.S())
s.BindHandler("/parse1", func(r *ghttp.Request) {
var users []*User
if err := r.Parse(&users); err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(users[0].Id, users[1].Id)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(client.PostContent(ctx,
"/parse1",
`[{"id":1,"name":"john","password1":"123Abc!@#","password2":"123Abc!@#"}, {"id":2,"name":"john","password1":"123Abc!@#","password2":"123Abc!@#"}]`),
`12`,
)
})
}
func Test_Params_Struct_Validation(t *testing.T) {
type User struct {
Id int `v:"required"`
Name string `v:"name@required-with:id"`
}
s := g.Server(guid.S())
s.Group("/", func(group *ghttp.RouterGroup) {
group.ALL("/", func(r *ghttp.Request) {
var (
err error
user *User
)
err = r.Parse(&user)
if err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit(user.Id, user.Name)
})
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
c := g.Client()
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(c.GetContent(ctx, "/", ``), `The Id field is required`)
t.Assert(c.GetContent(ctx, "/", `id=1&name=john`), `1john`)
t.Assert(c.PostContent(ctx, "/", `id=1&name=john&password1=123&password2=456`), `1john`)
t.Assert(c.PostContent(ctx, "/", `id=1`), `The name field is required`)
})
}
// https://github.com/gogf/gf/issues/1488
func Test_Params_Parse_Issue1488(t *testing.T) {
s := g.Server(guid.S())
s.Group("/", func(group *ghttp.RouterGroup) {
group.ALL("/", func(r *ghttp.Request) {
type Request struct {
Type []int `p:"type"`
Keyword string `p:"keyword"`
Limit int `p:"per_page" d:"10"`
Page int `p:"page" d:"1"`
Order string
CreatedAtLte string
CreatedAtGte string
CreatorID []int
}
for i := 0; i < 10; i++ {
r.SetParamMap(g.Map{
"type[]": 0,
"keyword": "",
"t_start": "",
"t_end": "",
"reserve_at_start": "",
"reserve_at_end": "",
"user_name": "",
"flag": "",
"per_page": 6,
})
var parsed Request
_ = r.Parse(&parsed)
r.Response.Write(parsed.Page, parsed.Limit)
}
})
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
c := g.Client()
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(c.GetContent(ctx, "/", ``), `16161616161616161616`)
})
}