github.com/gogf/gf/v2@v2.7.4/net/ghttp/ghttp_z_unit_issue_test.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package ghttp_test
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/gogf/gf/v2/encoding/gjson"
    16  	"github.com/gogf/gf/v2/encoding/gurl"
    17  	"github.com/gogf/gf/v2/frame/g"
    18  	"github.com/gogf/gf/v2/net/ghttp"
    19  	"github.com/gogf/gf/v2/test/gtest"
    20  	"github.com/gogf/gf/v2/text/gstr"
    21  	"github.com/gogf/gf/v2/util/gtag"
    22  	"github.com/gogf/gf/v2/util/guid"
    23  )
    24  
    25  // https://github.com/gogf/gf/issues/1609
    26  func Test_Issue1609(t *testing.T) {
    27  	s := g.Server(guid.S())
    28  	group := s.Group("/api/get")
    29  	group.GET("/", func(r *ghttp.Request) {
    30  		r.Response.Write("get")
    31  	})
    32  	s.SetDumpRouterMap(false)
    33  	gtest.Assert(s.Start(), nil)
    34  	defer s.Shutdown()
    35  
    36  	time.Sleep(100 * time.Millisecond)
    37  	gtest.C(t, func(t *gtest.T) {
    38  		c := g.Client()
    39  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
    40  
    41  		t.Assert(c.GetContent(ctx, "/api/get"), "get")
    42  		t.Assert(c.PostContent(ctx, "/test"), "Not Found")
    43  	})
    44  }
    45  
    46  func Test_Issue1611(t *testing.T) {
    47  	s := g.Server(guid.S())
    48  	v := g.View(guid.S())
    49  	content := "This is header"
    50  	gtest.AssertNil(v.SetPath(gtest.DataPath("issue1611")))
    51  	s.SetView(v)
    52  	s.BindHandler("/", func(r *ghttp.Request) {
    53  		gtest.AssertNil(r.Response.WriteTpl("index/layout.html", g.Map{
    54  			"header": content,
    55  		}))
    56  	})
    57  	s.SetDumpRouterMap(false)
    58  	s.Start()
    59  	defer s.Shutdown()
    60  
    61  	time.Sleep(100 * time.Millisecond)
    62  	gtest.C(t, func(t *gtest.T) {
    63  		c := g.Client()
    64  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
    65  
    66  		t.Assert(gstr.Contains(c.GetContent(ctx, "/"), content), true)
    67  	})
    68  }
    69  
    70  // https://github.com/gogf/gf/issues/1626
    71  func Test_Issue1626(t *testing.T) {
    72  	type TestReq struct {
    73  		Name string `v:"required"`
    74  	}
    75  	type TestRes struct {
    76  		Name string
    77  	}
    78  	s := g.Server(guid.S())
    79  	s.Use(
    80  		ghttp.MiddlewareHandlerResponse,
    81  		func(r *ghttp.Request) {
    82  			r.Middleware.Next()
    83  			if err := r.GetError(); err != nil {
    84  				r.Response.ClearBuffer()
    85  				r.Response.Write(err.Error())
    86  			}
    87  		},
    88  	)
    89  	s.BindHandler("/test", func(ctx context.Context, req *TestReq) (res *TestRes, err error) {
    90  		return &TestRes{Name: req.Name}, nil
    91  	})
    92  	s.SetDumpRouterMap(false)
    93  	s.Start()
    94  	defer s.Shutdown()
    95  
    96  	time.Sleep(100 * time.Millisecond)
    97  	gtest.C(t, func(t *gtest.T) {
    98  		c := g.Client()
    99  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   100  
   101  		t.Assert(c.GetContent(ctx, "/test"), `The Name field is required`)
   102  		t.Assert(
   103  			gstr.Contains(c.GetContent(ctx, "/test?name=john"), `{"Name":"john"}`),
   104  			true,
   105  		)
   106  	})
   107  }
   108  
   109  type Issue1653TestReq struct {
   110  	g.Meta    `path:"/test" method:"post" summary:"执行报表查询" tags:""`
   111  	UUID      string  `json:"uuid" v:"required#菜单唯一码不可为空" dc:""`
   112  	Limit     int     `json:"limit"`
   113  	Filter    []g.Map `json:"filter"`
   114  	FilterMap g.Map   `json:"filter_map"`
   115  }
   116  
   117  type Issue1653TestRes struct {
   118  	UUID     string      `json:"uuid"`
   119  	FeedBack interface{} `json:"feed_back"`
   120  }
   121  
   122  type cIssue1653Foo struct{}
   123  
   124  var Issue1653Foo = new(cIssue1653Foo)
   125  
   126  func (r cIssue1653Foo) PostTest(ctx context.Context, req *Issue1653TestReq) (*Issue1653TestRes, error) {
   127  	return &Issue1653TestRes{UUID: req.UUID, FeedBack: req.Filter[0]["code"]}, nil
   128  }
   129  
   130  func Test_Issue1653(t *testing.T) {
   131  	s := g.Server(guid.S())
   132  	s.Use(ghttp.MiddlewareHandlerResponse)
   133  	s.Group("/boot", func(grp *ghttp.RouterGroup) {
   134  		grp.Bind(Issue1653Foo)
   135  	})
   136  	s.SetDumpRouterMap(false)
   137  	s.Start()
   138  	defer s.Shutdown()
   139  	time.Sleep(1000 * time.Millisecond)
   140  	// g.Client()测试:
   141  	gtest.C(t, func(t *gtest.T) {
   142  		c := g.Client()
   143  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   144  		dataReq := `
   145  {"uuid":"28ee701c-7daf-4cdc-9a62-6d6704e6112b","limit":0,"filter":
   146  [
   147  {
   148  "code":"P00001","constraint":"",
   149  "created_at":"2022-03-08 04:56:15","created_by":"3ed72aba-1622-4262-a61e-83581e020763","default_value":"MonthStart()",
   150  "expression":"AND A.DLVDAT_0>='%v'","force":false,"frequent":true,"name":"发货日期起",
   151  "parent":"13109602-0da3-49b9-827f-2f44183ab756","read_only":false,"reference":null,"type":"date",
   152  "updated_at":"2022-03-08 04:56:15","updated_by":"3ed72aba-1622-4262-a61e-83581e020763","updated_tick":1,
   153  "uuid":"e6cd3268-1d75-42e0-83f9-f1f7b29976e8"
   154  },
   155  {
   156  "code":"P00002","constraint":"","created_at":"2022-03-08 04:56:15","created_by":
   157  "3ed72aba-1622-4262-a61e-83581e020763","default_value":"MonthEnd()","expression":"AND A.DLVDAT_0<='%v'","force":false,"frequent":true,
   158  "name":"发货日期止","parent":"13109602-0da3-49b9-827f-2f44183ab756","read_only":false,"reference":null,"type":"date","updated_at":
   159  "2022-03-08 04:56:15","updated_by":"3ed72aba-1622-4262-a61e-83581e020763","updated_tick":1,"uuid":"dba005b5-655e-4ac4-8b22-898aa3ad2294"
   160  }
   161  ],
   162  "filter_map":{"P00001":1646064000000,"P00002":1648742399999},
   163  "selector_template":""
   164  }
   165  `
   166  		resContent := c.PostContent(ctx, "/boot/test", dataReq)
   167  		t.Assert(resContent, `{"code":0,"message":"","data":{"uuid":"28ee701c-7daf-4cdc-9a62-6d6704e6112b","feed_back":"P00001"}}`)
   168  	})
   169  }
   170  
   171  type LbseMasterHead struct {
   172  	Code     string   `json:"code" v:"code@required|min-length:1#The code is required"`
   173  	Active   bool     `json:"active"`
   174  	Preset   bool     `json:"preset"`
   175  	Superior string   `json:"superior"`
   176  	Path     []string `json:"path"`
   177  	Sort     int      `json:"sort"`
   178  	Folder   bool     `json:"folder"`
   179  	Test     string   `json:"test" v:"required"`
   180  }
   181  
   182  type Template struct {
   183  	LbseMasterHead
   184  	Datasource string `json:"datasource" v:"required|length:32,32#The datasource is required"`
   185  	SQLText    string `json:"sql_text"`
   186  }
   187  
   188  type TemplateCreateReq struct {
   189  	g.Meta `path:"/test" method:"post" summary:"Create template" tags:"Template"`
   190  	Master Template `json:"master"`
   191  }
   192  
   193  type TemplateCreateRes struct{}
   194  
   195  type cFoo1 struct{}
   196  
   197  var Foo1 = new(cFoo1)
   198  
   199  func (r cFoo1) PostTest1(ctx context.Context, req *TemplateCreateReq) (res *TemplateCreateRes, err error) {
   200  	g.Dump(req)
   201  	return
   202  }
   203  
   204  // https://github.com/gogf/gf/issues/1662
   205  func Test_Issue662(t *testing.T) {
   206  	s := g.Server(guid.S())
   207  	s.Use(ghttp.MiddlewareHandlerResponse)
   208  	s.Group("/boot", func(grp *ghttp.RouterGroup) {
   209  		grp.Bind(Foo1)
   210  	})
   211  	s.SetDumpRouterMap(false)
   212  	s.Start()
   213  	defer s.Shutdown()
   214  	time.Sleep(1000 * time.Millisecond)
   215  
   216  	// g.Client()测试:
   217  	// code字段传入空字符串时,校验没有提示
   218  	gtest.C(t, func(t *gtest.T) {
   219  		c := g.Client()
   220  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   221  		dataReq := `
   222  {"master":{"active":true,"code":"","created_at":"","created_by":"","created_by_text":"","datasource":"38b6f170-a584-43fc-8912-cc1e9bf1b1a9","description":"币种","folder":false,"path":"[\"XCUR\"]","preset":false,"sort":1000,"sql_text":"SELECT!!!!","superior":null,"updated_at":"","updated_by":"","updated_by_text":"","updated_tick":0,"uuid":""},"translation":[{"code":"zh_CN","text":"币种"},{"code":"en_US","text":"币种"}],"filters":null,"fields":[{"code":"F001","created_at":"2022-01-18 23:37:38","created_by":"3ed72aba-1622-4262-a61e-83581e020763","field":"value","hide":false,"min_width":120,"name":"value","parent":"296154bf-b718-4e8f-8b70-efb969b831ec","updated_at":"2022-01-18 23:37:38","updated_by":"3ed72aba-1622-4262-a61e-83581e020763","updated_tick":1,"uuid":"f2140b7a-044c-41c3-b70e-852e6160b21b"},{"code":"F002","created_at":"2022-01-18 23:37:38","created_by":"3ed72aba-1622-4262-a61e-83581e020763","field":"label","hide":false,"min_width":120,"name":"label","parent":"296154bf-b718-4e8f-8b70-efb969b831ec","updated_at":"2022-01-18 23:37:38","updated_by":"3ed72aba-1622-4262-a61e-83581e020763","updated_tick":1,"uuid":"2d3bba5d-308b-4dba-bcac-f093e6556eca"}],"limit":0}
   223  `
   224  		t.Assert(c.PostContent(ctx, "/boot/test", dataReq), `{"code":51,"message":"The code is required","data":null}`)
   225  	})
   226  }
   227  
   228  type DemoReq struct {
   229  	g.Meta `path:"/demo" method:"post"`
   230  	Data   *gjson.Json
   231  }
   232  
   233  type DemoRes struct {
   234  	Content string
   235  }
   236  
   237  type Api struct{}
   238  
   239  func (a *Api) Demo(ctx context.Context, req *DemoReq) (res *DemoRes, err error) {
   240  	return &DemoRes{
   241  		Content: req.Data.MustToJsonString(),
   242  	}, err
   243  }
   244  
   245  var api = Api{}
   246  
   247  // https://github.com/gogf/gf/issues/2172
   248  func Test_Issue2172(t *testing.T) {
   249  	s := g.Server(guid.S())
   250  	s.Use(ghttp.MiddlewareHandlerResponse)
   251  	s.Group("/", func(group *ghttp.RouterGroup) {
   252  		group.Bind(api)
   253  	})
   254  	s.SetDumpRouterMap(false)
   255  	s.Start()
   256  	defer s.Shutdown()
   257  	time.Sleep(1000 * time.Millisecond)
   258  
   259  	gtest.C(t, func(t *gtest.T) {
   260  		c := g.Client()
   261  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   262  		dataReq := `{"data":{"asd":1}}`
   263  		t.Assert(c.PostContent(ctx, "/demo", dataReq), `{"code":0,"message":"","data":{"Content":"{\"asd\":1}"}}`)
   264  	})
   265  }
   266  
   267  // https://github.com/gogf/gf/issues/2334
   268  func Test_Issue2334(t *testing.T) {
   269  	s := g.Server(guid.S())
   270  	s.SetServerRoot(gtest.DataPath("static1"))
   271  	s.SetDumpRouterMap(false)
   272  	s.Start()
   273  	defer s.Shutdown()
   274  	time.Sleep(1000 * time.Millisecond)
   275  	gtest.C(t, func(t *gtest.T) {
   276  		c := g.Client()
   277  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   278  		t.Assert(c.GetContent(ctx, "/index.html"), "index")
   279  
   280  		c.SetHeader("If-Modified-Since", "Mon, 12 Dec 2040 05:53:35 GMT")
   281  		res, _ := c.Get(ctx, "/index.html")
   282  		t.Assert(res.StatusCode, 304)
   283  	})
   284  }
   285  
   286  type CreateOrderReq struct {
   287  	g.Meta  `path:"/order" tags:"订单" method:"put" summary:"创建订单"`
   288  	Details []*OrderDetail `p:"detail" v:"required#请输入订单详情" dc:"订单详情"`
   289  }
   290  
   291  type OrderDetail struct {
   292  	Name   string  `p:"name" v:"required#请输入物料名称" dc:"物料名称"`
   293  	Sn     string  `p:"sn" v:"required#请输入客户编号" dc:"客户编号"`
   294  	Images string  `p:"images" dc:"图片"`
   295  	Desc   string  `p:"desc" dc:"备注"`
   296  	Number int     `p:"number" v:"required#请输入数量" dc:"数量"`
   297  	Price  float64 `p:"price" v:"required" dc:"单价"`
   298  }
   299  
   300  type CreateOrderRes struct{}
   301  type OrderController struct{}
   302  
   303  func (c *OrderController) CreateOrder(ctx context.Context, req *CreateOrderReq) (res *CreateOrderRes, err error) {
   304  	return
   305  }
   306  
   307  // https://github.com/gogf/gf/issues/2482
   308  func Test_Issue2482(t *testing.T) {
   309  	s := g.Server(guid.S())
   310  	s.Group("/api/v2", func(group *ghttp.RouterGroup) {
   311  		group.Middleware(ghttp.MiddlewareHandlerResponse)
   312  		group.Bind(OrderController{})
   313  	})
   314  	s.SetDumpRouterMap(false)
   315  	s.Start()
   316  	defer s.Shutdown()
   317  	time.Sleep(1000 * time.Millisecond)
   318  
   319  	c := g.Client()
   320  	c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   321  	gtest.C(t, func(t *gtest.T) {
   322  		content := `
   323  {
   324      "detail": [
   325        {
   326          "images": "string",
   327          "desc": "string",
   328          "number": 0,
   329          "price": 0
   330        }
   331      ]
   332    }
   333  `
   334  		t.Assert(c.PutContent(ctx, "/api/v2/order", content), `{"code":51,"message":"请输入物料名称","data":null}`)
   335  	})
   336  	gtest.C(t, func(t *gtest.T) {
   337  		content := `
   338  {
   339      "detail": [
   340        {
   341          "images": "string",
   342          "desc": "string",
   343          "number": 0,
   344  		"name": "string",
   345          "price": 0
   346        }
   347      ]
   348    }
   349  `
   350  		t.Assert(c.PutContent(ctx, "/api/v2/order", content), `{"code":51,"message":"请输入客户编号","data":null}`)
   351  	})
   352  	gtest.C(t, func(t *gtest.T) {
   353  		content := `
   354  {
   355      "detail": [
   356        {
   357          "images": "string",
   358          "desc": "string",
   359          "number": 0,
   360  		"name": "string",
   361  		"sn": "string",
   362          "price": 0
   363        }
   364      ]
   365    }
   366  `
   367  		t.Assert(c.PutContent(ctx, "/api/v2/order", content), `{"code":0,"message":"","data":null}`)
   368  	})
   369  }
   370  
   371  type Issue2890Enum string
   372  
   373  const (
   374  	Issue2890EnumA Issue2890Enum = "a"
   375  	Issue2890EnumB Issue2890Enum = "b"
   376  )
   377  
   378  type Issue2890Req struct {
   379  	g.Meta `path:"/issue2890" method:"post"`
   380  	Id     int
   381  	Enums  Issue2890Enum `v:"required|enums"`
   382  }
   383  
   384  type Issue2890Res struct{}
   385  type Issue2890Controller struct{}
   386  
   387  func (c *Issue2890Controller) Post(ctx context.Context, req *Issue2890Req) (res *Issue2890Res, err error) {
   388  	g.RequestFromCtx(ctx).Response.Write(req.Enums)
   389  	return
   390  }
   391  
   392  // https://github.com/gogf/gf/issues/2890
   393  func Test_Issue2890(t *testing.T) {
   394  	gtest.C(t, func(t *gtest.T) {
   395  		oldEnumsJson, err := gtag.GetGlobalEnums()
   396  		t.AssertNil(err)
   397  		defer t.AssertNil(gtag.SetGlobalEnums(oldEnumsJson))
   398  
   399  		err = gtag.SetGlobalEnums(`{"github.com/gogf/gf/v2/net/ghttp_test.Issue2890Enum": ["a","b"]}`)
   400  		t.AssertNil(err)
   401  
   402  		s := g.Server(guid.S())
   403  		s.Group("/api/v2", func(group *ghttp.RouterGroup) {
   404  			group.Middleware(ghttp.MiddlewareHandlerResponse)
   405  			group.Bind(Issue2890Controller{})
   406  		})
   407  		s.SetDumpRouterMap(false)
   408  		s.Start()
   409  		defer s.Shutdown()
   410  		time.Sleep(1000 * time.Millisecond)
   411  
   412  		c := g.Client()
   413  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   414  		t.Assert(
   415  			c.PostContent(ctx, "/api/v2/issue2890", ``),
   416  			`{"code":51,"message":"The Enums field is required","data":null}`,
   417  		)
   418  		t.Assert(
   419  			c.PostContent(ctx, "/api/v2/issue2890", `{"Enums":"c"}`),
   420  			"{\"code\":51,\"message\":\"The Enums value `c` should be in enums of: [\\\"a\\\",\\\"b\\\"]\",\"data\":null}",
   421  		)
   422  	})
   423  }
   424  
   425  // https://github.com/gogf/gf/issues/2963
   426  func Test_Issue2963(t *testing.T) {
   427  	gtest.C(t, func(t *gtest.T) {
   428  		s := g.Server(guid.S())
   429  		s.SetServerRoot(gtest.DataPath("issue2963"))
   430  		s.SetDumpRouterMap(false)
   431  		s.Start()
   432  		defer s.Shutdown()
   433  		time.Sleep(100 * time.Millisecond)
   434  
   435  		c := g.Client()
   436  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   437  		t.Assert(c.GetContent(ctx, "/1.txt"), `1`)
   438  		t.Assert(c.GetContent(ctx, "/中文G146(1)-icon.txt"), `中文G146(1)-icon`)
   439  		t.Assert(c.GetContent(ctx, "/"+gurl.Encode("中文G146(1)-icon.txt")), `中文G146(1)-icon`)
   440  	})
   441  }
   442  
   443  type Issue3077Req struct {
   444  	g.Meta `path:"/echo" method:"get"`
   445  	A      string `default:"a"`
   446  	B      string `default:""`
   447  }
   448  type Issue3077Res struct {
   449  	g.Meta `mime:"text/html"`
   450  }
   451  
   452  type Issue3077V1 struct{}
   453  
   454  func (c *Issue3077V1) Hello(ctx context.Context, req *Issue3077Req) (res *Issue3077Res, err error) {
   455  	g.RequestFromCtx(ctx).Response.Write(fmt.Sprintf("%v", req))
   456  	return
   457  }
   458  
   459  // https://github.com/gogf/gf/issues/3077
   460  func Test_Issue3077(t *testing.T) {
   461  	gtest.C(t, func(t *gtest.T) {
   462  		s := g.Server(guid.S())
   463  		s.Group("/", func(group *ghttp.RouterGroup) {
   464  			group.Bind(Issue3077V1{})
   465  		})
   466  		s.SetDumpRouterMap(false)
   467  		s.Start()
   468  		defer s.Shutdown()
   469  		time.Sleep(100 * time.Millisecond)
   470  
   471  		c := g.Client()
   472  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   473  		t.Assert(c.GetContent(ctx, "/echo?a=1&b=2"), `&{{} 1 2}`)
   474  		t.Assert(c.GetContent(ctx, "/echo?"), `&{{} a }`)
   475  	})
   476  }
   477  
   478  type ListMessageReq struct {
   479  	g.Meta    `path:"/list" method:"get"`
   480  	StartTime int64
   481  	EndTime   int64
   482  }
   483  type ListMessageRes struct {
   484  	g.Meta
   485  	Title   string
   486  	Content string
   487  }
   488  type BaseRes[T any] struct {
   489  	g.Meta
   490  	Code int
   491  	Data T
   492  	Msg  string
   493  }
   494  type cMessage struct{}
   495  
   496  func (c *cMessage) List(ctx context.Context, req *ListMessageReq) (res *BaseRes[*ListMessageRes], err error) {
   497  	res = &BaseRes[*ListMessageRes]{
   498  		Code: 100,
   499  		Data: &ListMessageRes{
   500  			Title:   "title",
   501  			Content: "hello",
   502  		},
   503  	}
   504  	return res, err
   505  }
   506  
   507  // https://github.com/gogf/gf/issues/2457
   508  func Test_Issue2457(t *testing.T) {
   509  	gtest.C(t, func(t *gtest.T) {
   510  		s := g.Server(guid.S())
   511  		s.Use(ghttp.MiddlewareHandlerResponse)
   512  		s.Group("/", func(group *ghttp.RouterGroup) {
   513  			group.Bind(
   514  				new(cMessage),
   515  			)
   516  		})
   517  		s.SetDumpRouterMap(false)
   518  		s.Start()
   519  		defer s.Shutdown()
   520  		time.Sleep(100 * time.Millisecond)
   521  
   522  		c := g.Client()
   523  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   524  		t.Assert(c.GetContent(ctx, "/list"), `{"code":0,"message":"","data":{"Code":100,"Data":{"Title":"title","Content":"hello"},"Msg":""}}`)
   525  	})
   526  }
   527  
   528  // https://github.com/gogf/gf/issues/3245
   529  type Issue3245Req struct {
   530  	g.Meta      `path:"/hello" method:"get"`
   531  	Name        string `p:"nickname" json:"name"`
   532  	XHeaderName string `p:"Header-Name" in:"header" json:"X-Header-Name"`
   533  	XHeaderAge  uint8  `p:"Header-Age" in:"cookie" json:"X-Header-Age"`
   534  }
   535  type Issue3245Res struct {
   536  	Reply any
   537  }
   538  
   539  type Issue3245V1 struct{}
   540  
   541  func (Issue3245V1) Hello(ctx context.Context, req *Issue3245Req) (res *Issue3245Res, err error) {
   542  	res = &Issue3245Res{
   543  		Reply: req,
   544  	}
   545  	return
   546  }
   547  
   548  func Test_Issue3245(t *testing.T) {
   549  	gtest.C(t, func(t *gtest.T) {
   550  		s := g.Server(guid.S())
   551  		s.Use(ghttp.MiddlewareHandlerResponse)
   552  		s.Group("/", func(group *ghttp.RouterGroup) {
   553  			group.Bind(
   554  				new(Issue3245V1),
   555  			)
   556  		})
   557  		s.SetDumpRouterMap(false)
   558  		s.Start()
   559  		defer s.Shutdown()
   560  		time.Sleep(100 * time.Millisecond)
   561  
   562  		c := g.Client()
   563  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   564  		c.SetHeader("Header-Name", "oldme")
   565  		c.SetCookie("Header-Age", "25")
   566  
   567  		expect := `{"code":0,"message":"","data":{"Reply":{"name":"oldme","X-Header-Name":"oldme","X-Header-Age":25}}}`
   568  		t.Assert(c.GetContent(ctx, "/hello?nickname=oldme"), expect)
   569  	})
   570  }
   571  
   572  type ItemSecondThird struct {
   573  	SecondID uint64 `json:"secondId,string"`
   574  	ThirdID  uint64 `json:"thirdId,string"`
   575  }
   576  type ItemFirst struct {
   577  	ID uint64 `json:"id,string"`
   578  	ItemSecondThird
   579  }
   580  type ItemInput struct {
   581  	ItemFirst
   582  }
   583  type Issue3789Req struct {
   584  	g.Meta `path:"/hello" method:"GET"`
   585  	ItemInput
   586  }
   587  type Issue3789Res struct {
   588  	ItemInput
   589  }
   590  
   591  type Issue3789 struct{}
   592  
   593  func (Issue3789) Say(ctx context.Context, req *Issue3789Req) (res *Issue3789Res, err error) {
   594  	res = &Issue3789Res{
   595  		ItemInput: req.ItemInput,
   596  	}
   597  	return
   598  }
   599  
   600  // https://github.com/gogf/gf/issues/3789
   601  func Test_Issue3789(t *testing.T) {
   602  	gtest.C(t, func(t *gtest.T) {
   603  		s := g.Server()
   604  		s.Use(ghttp.MiddlewareHandlerResponse)
   605  		s.Group("/", func(group *ghttp.RouterGroup) {
   606  			group.Bind(
   607  				new(Issue3789),
   608  			)
   609  		})
   610  		s.SetDumpRouterMap(false)
   611  		s.Start()
   612  		defer s.Shutdown()
   613  		time.Sleep(100 * time.Millisecond)
   614  
   615  		c := g.Client()
   616  		c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
   617  		expect := `{"code":0,"message":"","data":{"id":"0","secondId":"2","thirdId":"3"}}`
   618  		t.Assert(c.GetContent(ctx, "/hello?id=&secondId=2&thirdId=3"), expect)
   619  	})
   620  }