How to use NoBody method of tdhttp Package

Best Go-testdeep code snippet using tdhttp.NoBody

test_api_test.go

Source:test_api_test.go Github

copy

Full Screen

...125 CmpHeader(containsKey).126 CmpHeader(td.SuperMapOf(http.Header{}, td.MapEntries{127 "X-Testdeep-Method": td.Bag(td.Re(`(?i)^head\z`)),128 })).129 NoBody().130 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {131 assert.Cmp(resp.StatusCode, 200)132 assert.Cmp(resp.Header, containsKey)133 assert.Smuggle(resp.Body, io.ReadAll, td.Empty())134 })).135 Failed())136 td.CmpEmpty(t, mockT.LogBuf())137 mockT = tdutil.NewT("test")138 td.CmpFalse(t,139 tdhttp.NewTestAPI(mockT, mux).140 Head("/any").141 CmpStatus(200).142 CmpHeader(containsKey).143 CmpBody(td.Empty()).144 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {145 assert.Cmp(resp.StatusCode, 200)146 assert.Cmp(resp.Header, containsKey)147 assert.Smuggle(resp.Body, io.ReadAll, td.Empty())148 })).149 Failed())150 td.CmpEmpty(t, mockT.LogBuf())151 mockT = tdutil.NewT("test")152 td.CmpFalse(t,153 tdhttp.NewTestAPI(mockT, mux).154 Get("/any").155 CmpStatus(200).156 CmpHeader(containsKey).157 CmpBody("GET!").158 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {159 assert.Cmp(resp.StatusCode, 200)160 assert.Cmp(resp.Header, containsKey)161 assert.Smuggle(resp.Body, io.ReadAll, td.String("GET!"))162 })).163 Failed())164 td.CmpEmpty(t, mockT.LogBuf())165 mockT = tdutil.NewT("test")166 td.CmpFalse(t,167 tdhttp.NewTestAPI(mockT, mux).168 Get("/any").169 CmpStatus(200).170 CmpHeader(containsKey).171 CmpBody(td.Contains("GET")).172 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {173 assert.Cmp(resp.StatusCode, 200)174 assert.Cmp(resp.Header, containsKey)175 assert.Smuggle(resp.Body, io.ReadAll, td.Contains("GET"))176 })).177 Failed())178 td.CmpEmpty(t, mockT.LogBuf())179 mockT = tdutil.NewT("test")180 td.CmpFalse(t,181 tdhttp.NewTestAPI(mockT, mux).182 Options("/any", strings.NewReader("OPTIONS body")).183 CmpStatus(200).184 CmpHeader(containsKey).185 CmpBody("OPTIONS!\n---\nOPTIONS body").186 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {187 assert.Cmp(resp.StatusCode, 200)188 assert.Cmp(resp.Header, containsKey)189 assert.Smuggle(resp.Body, io.ReadAll, td.String("OPTIONS!\n---\nOPTIONS body"))190 })).191 Failed())192 td.CmpEmpty(t, mockT.LogBuf())193 mockT = tdutil.NewT("test")194 td.CmpFalse(t,195 tdhttp.NewTestAPI(mockT, mux).196 Post("/any", strings.NewReader("POST body")).197 CmpStatus(200).198 CmpHeader(containsKey).199 CmpBody("POST!\n---\nPOST body").200 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {201 assert.Cmp(resp.StatusCode, 200)202 assert.Cmp(resp.Header, containsKey)203 assert.Smuggle(resp.Body, io.ReadAll, td.String("POST!\n---\nPOST body"))204 })).205 Failed())206 td.CmpEmpty(t, mockT.LogBuf())207 mockT = tdutil.NewT("test")208 td.CmpFalse(t,209 tdhttp.NewTestAPI(mockT, mux).210 PostForm("/any", url.Values{"p1": []string{"v1"}, "p2": []string{"v2"}}).211 CmpStatus(200).212 CmpHeader(containsKey).213 CmpBody("POST!\n---\np1=v1&p2=v2").214 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {215 assert.Cmp(resp.StatusCode, 200)216 assert.Cmp(resp.Header, containsKey)217 assert.Smuggle(resp.Body, io.ReadAll, td.String("POST!\n---\np1=v1&p2=v2"))218 })).219 Failed())220 td.CmpEmpty(t, mockT.LogBuf())221 mockT = tdutil.NewT("test")222 td.CmpFalse(t,223 tdhttp.NewTestAPI(mockT, mux).224 PostForm("/any", tdhttp.Q{"p1": "v1", "p2": "v2"}).225 CmpStatus(200).226 CmpHeader(containsKey).227 CmpBody("POST!\n---\np1=v1&p2=v2").228 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {229 assert.Cmp(resp.StatusCode, 200)230 assert.Cmp(resp.Header, containsKey)231 assert.Smuggle(resp.Body, io.ReadAll, td.String("POST!\n---\np1=v1&p2=v2"))232 })).233 Failed())234 td.CmpEmpty(t, mockT.LogBuf())235 mockT = tdutil.NewT("test")236 td.CmpFalse(t,237 tdhttp.NewTestAPI(mockT, mux).238 PostMultipartFormData("/any", &tdhttp.MultipartBody{239 Boundary: "BoUnDaRy",240 Parts: []*tdhttp.MultipartPart{241 tdhttp.NewMultipartPartString("pipo", "bingo"),242 },243 }).244 CmpStatus(200).245 CmpHeader(containsKey).246 CmpBody(strings.ReplaceAll(247 `POST!248---249--BoUnDaRy%CR250Content-Disposition: form-data; name="pipo"%CR251Content-Type: text/plain; charset=utf-8%CR252%CR253bingo%CR254--BoUnDaRy--%CR255`,256 "%CR", "\r")).257 Failed())258 td.CmpEmpty(t, mockT.LogBuf())259 mockT = tdutil.NewT("test")260 td.CmpFalse(t,261 tdhttp.NewTestAPI(mockT, mux).262 Put("/any", strings.NewReader("PUT body")).263 CmpStatus(200).264 CmpHeader(containsKey).265 CmpBody("PUT!\n---\nPUT body").266 Failed())267 td.CmpEmpty(t, mockT.LogBuf())268 mockT = tdutil.NewT("test")269 td.CmpFalse(t,270 tdhttp.NewTestAPI(mockT, mux).271 Patch("/any", strings.NewReader("PATCH body")).272 CmpStatus(200).273 CmpHeader(containsKey).274 CmpBody("PATCH!\n---\nPATCH body").275 Failed())276 td.CmpEmpty(t, mockT.LogBuf())277 mockT = tdutil.NewT("test")278 td.CmpFalse(t,279 tdhttp.NewTestAPI(mockT, mux).280 Delete("/any", strings.NewReader("DELETE body")).281 CmpStatus(200).282 CmpHeader(containsKey).283 CmpBody("DELETE!\n---\nDELETE body").284 Failed())285 td.CmpEmpty(t, mockT.LogBuf())286 })287 t.Run("No JSON error", func(t *testing.T) {288 requestBody := map[string]any{"hey": 123}289 expectedBody := func(m string) td.TestDeep {290 return td.JSON(`{"method": $1, "body": {"hey": 123}}`, m)291 }292 mockT := tdutil.NewT("test")293 td.CmpFalse(t,294 tdhttp.NewTestAPI(mockT, mux).295 NewJSONRequest("GET", "/mirror/json", json.RawMessage(`null`)).296 CmpStatus(200).297 CmpHeader(containsKey).298 CmpJSONBody(nil).299 Failed())300 td.CmpEmpty(t, mockT.LogBuf())301 mockT = tdutil.NewT("test")302 td.CmpFalse(t,303 tdhttp.NewTestAPI(mockT, mux).304 NewJSONRequest("ZIP", "/any/json", requestBody).305 CmpStatus(200).306 CmpHeader(containsKey).307 CmpJSONBody(expectedBody("ZIP")).308 Failed())309 td.CmpEmpty(t, mockT.LogBuf())310 mockT = tdutil.NewT("test")311 td.CmpFalse(t,312 tdhttp.NewTestAPI(mockT, mux).313 NewJSONRequest("ZIP", "/any/json", requestBody).314 CmpStatus(200).315 CmpHeader(containsKey).316 CmpJSONBody(td.JSONPointer("/body/hey", 123)).317 Failed())318 td.CmpEmpty(t, mockT.LogBuf())319 mockT = tdutil.NewT("test")320 td.CmpFalse(t,321 tdhttp.NewTestAPI(mockT, mux).322 PostJSON("/any/json", requestBody).323 CmpStatus(200).324 CmpHeader(containsKey).325 CmpJSONBody(expectedBody("POST")).326 Failed())327 td.CmpEmpty(t, mockT.LogBuf())328 mockT = tdutil.NewT("test")329 td.CmpFalse(t,330 tdhttp.NewTestAPI(mockT, mux).331 PutJSON("/any/json", requestBody).332 CmpStatus(200).333 CmpHeader(containsKey).334 CmpJSONBody(expectedBody("PUT")).335 Failed())336 td.CmpEmpty(t, mockT.LogBuf())337 mockT = tdutil.NewT("test")338 td.CmpFalse(t,339 tdhttp.NewTestAPI(mockT, mux).340 PatchJSON("/any/json", requestBody).341 CmpStatus(200).342 CmpHeader(containsKey).343 CmpJSONBody(expectedBody("PATCH")).344 Failed())345 td.CmpEmpty(t, mockT.LogBuf())346 mockT = tdutil.NewT("test")347 td.CmpFalse(t,348 tdhttp.NewTestAPI(mockT, mux).349 DeleteJSON("/any/json", requestBody).350 CmpStatus(200).351 CmpHeader(containsKey).352 CmpJSONBody(expectedBody("DELETE")).353 Failed())354 td.CmpEmpty(t, mockT.LogBuf())355 // With anchors356 type ReqBody struct {357 Hey int `json:"hey"`358 }359 type Resp struct {360 Method string `json:"method"`361 ReqBody ReqBody `json:"body"`362 }363 mockT = tdutil.NewT("test")364 tt := td.NewT(mockT)365 td.CmpFalse(t,366 tdhttp.NewTestAPI(mockT, mux).367 DeleteJSON("/any/json", requestBody).368 CmpStatus(200).369 CmpHeader(containsKey).370 CmpJSONBody(Resp{371 Method: tt.A(td.Re(`^(?i)delete\z`), "").(string),372 ReqBody: ReqBody{373 Hey: tt.A(td.Between(120, 130)).(int),374 },375 }).376 Failed())377 td.CmpEmpty(t, mockT.LogBuf())378 // JSON and root operator (here SuperMapOf)379 mockT = tdutil.NewT("test")380 td.CmpFalse(t,381 tdhttp.NewTestAPI(mockT, mux).382 PostJSON("/any/json", true).383 CmpStatus(200).384 CmpJSONBody(td.JSON(`SuperMapOf({"body":Ignore()})`)).385 Failed())386 td.CmpEmpty(t, mockT.LogBuf())387 // td.Bag+td.JSON388 mockT = tdutil.NewT("test")389 td.CmpFalse(t,390 tdhttp.NewTestAPI(mockT, mux).391 PostJSON("/mirror/json",392 json.RawMessage(`[{"name":"Bob"},{"name":"Alice"}]`)).393 CmpStatus(200).394 CmpJSONBody(td.Bag(395 td.JSON(`{"name":"Alice"}`),396 td.JSON(`{"name":"Bob"}`),397 )).398 Failed())399 td.CmpEmpty(t, mockT.LogBuf())400 // td.Bag+literal401 type People struct {402 Name string `json:"name"`403 }404 mockT = tdutil.NewT("test")405 td.CmpFalse(t,406 tdhttp.NewTestAPI(mockT, mux).407 PostJSON("/mirror/json",408 json.RawMessage(`[{"name":"Bob"},{"name":"Alice"}]`)).409 CmpStatus(200).410 CmpJSONBody(td.Bag(People{"Alice"}, People{"Bob"})).411 Failed())412 td.CmpEmpty(t, mockT.LogBuf())413 })414 t.Run("No XML error", func(t *testing.T) {415 type XBody struct {416 Hey int `xml:"hey"`417 }418 type XResp struct {419 Method string `xml:"method"`420 ReqBody *XBody `xml:"XBody"`421 }422 requestBody := XBody{Hey: 123}423 expectedBody := func(m string) XResp {424 return XResp{425 Method: m,426 ReqBody: &requestBody,427 }428 }429 mockT := tdutil.NewT("test")430 td.CmpFalse(t,431 tdhttp.NewTestAPI(mockT, mux).432 NewXMLRequest("ZIP", "/any/xml", requestBody).433 CmpStatus(200).434 CmpHeader(containsKey).435 CmpXMLBody(expectedBody("ZIP")).436 Failed())437 td.CmpEmpty(t, mockT.LogBuf())438 mockT = tdutil.NewT("test")439 td.CmpFalse(t,440 tdhttp.NewTestAPI(mockT, mux).441 PostXML("/any/xml", requestBody).442 CmpStatus(200).443 CmpHeader(containsKey).444 CmpXMLBody(expectedBody("POST")).445 Failed())446 td.CmpEmpty(t, mockT.LogBuf())447 mockT = tdutil.NewT("test")448 td.CmpFalse(t,449 tdhttp.NewTestAPI(mockT, mux).450 PutXML("/any/xml", requestBody).451 CmpStatus(200).452 CmpHeader(containsKey).453 CmpXMLBody(expectedBody("PUT")).454 Failed())455 td.CmpEmpty(t, mockT.LogBuf())456 mockT = tdutil.NewT("test")457 td.CmpFalse(t,458 tdhttp.NewTestAPI(mockT, mux).459 PatchXML("/any/xml", requestBody).460 CmpStatus(200).461 CmpHeader(containsKey).462 CmpXMLBody(expectedBody("PATCH")).463 Failed())464 td.CmpEmpty(t, mockT.LogBuf())465 mockT = tdutil.NewT("test")466 td.CmpFalse(t,467 tdhttp.NewTestAPI(mockT, mux).468 DeleteXML("/any/xml", requestBody).469 CmpStatus(200).470 CmpHeader(containsKey).471 CmpXMLBody(expectedBody("DELETE")).472 Failed())473 td.CmpEmpty(t, mockT.LogBuf())474 // With anchors475 mockT = tdutil.NewT("test")476 tt := td.NewT(mockT)477 td.CmpFalse(tt,478 tdhttp.NewTestAPI(mockT, mux).479 DeleteXML("/any/xml", requestBody).480 CmpStatus(200).481 CmpHeader(containsKey).482 CmpXMLBody(XResp{483 Method: tt.A(td.Re(`^(?i)delete\z`), "").(string),484 ReqBody: &XBody{485 Hey: tt.A(td.Between(120, 130)).(int),486 },487 }).488 Failed())489 td.CmpEmpty(t, mockT.LogBuf())490 })491 t.Run("Cookies", func(t *testing.T) {492 mockT := tdutil.NewT("test")493 td.CmpFalse(t,494 tdhttp.NewTestAPI(mockT, mux).495 Get("/any/cookies").496 CmpCookies([]*http.Cookie{497 {498 Name: "first",499 Value: "cookie1",500 MaxAge: 123456,501 Expires: time.Date(2021, time.August, 12, 11, 22, 33, 0, time.UTC),502 },503 {504 Name: "second",505 Value: "cookie2",506 MaxAge: 654321,507 },508 }).509 Failed())510 td.CmpEmpty(t, mockT.LogBuf())511 mockT = tdutil.NewT("test")512 td.CmpTrue(t,513 tdhttp.NewTestAPI(mockT, mux).514 Get("/any/cookies").515 CmpCookies([]*http.Cookie{516 {517 Name: "first",518 Value: "cookie1",519 MaxAge: 123456,520 Expires: time.Date(2021, time.August, 12, 11, 22, 33, 0, time.UTC),521 },522 }).523 Failed())524 td.CmpContains(t, mockT.LogBuf(),525 "Failed test 'cookies should match'")526 td.CmpContains(t, mockT.LogBuf(),527 "Response.Cookie: comparing slices, from index #1")528 // 2 cookies are here whatever their order is using Bag529 mockT = tdutil.NewT("test")530 td.CmpFalse(t,531 tdhttp.NewTestAPI(mockT, mux).532 Get("/any/cookies").533 CmpCookies(td.Bag(534 td.Smuggle("Name", "second"),535 td.Smuggle("Name", "first"),536 )).537 Failed())538 td.CmpEmpty(t, mockT.LogBuf())539 // Testing only Name & Value whatever their order is using Bag540 mockT = tdutil.NewT("test")541 td.CmpFalse(t,542 tdhttp.NewTestAPI(mockT, mux).543 Get("/any/cookies").544 CmpCookies(td.Bag(545 td.Struct(&http.Cookie{Name: "first", Value: "cookie1"}, nil),546 td.Struct(&http.Cookie{Name: "second", Value: "cookie2"}, nil),547 )).548 Failed())549 td.CmpEmpty(t, mockT.LogBuf())550 // Testing the presence of only one using SuperBagOf551 mockT = tdutil.NewT("test")552 td.CmpFalse(t,553 tdhttp.NewTestAPI(mockT, mux).554 Get("/any/cookies").555 CmpCookies(td.SuperBagOf(556 td.Struct(&http.Cookie{Name: "first", Value: "cookie1"}, nil),557 )).558 Failed())559 td.CmpEmpty(t, mockT.LogBuf())560 // Testing only the number of cookies561 mockT = tdutil.NewT("test")562 td.CmpFalse(t,563 tdhttp.NewTestAPI(mockT, mux).564 Get("/any/cookies").565 CmpCookies(td.Len(2)).566 Failed())567 td.CmpEmpty(t, mockT.LogBuf())568 // Error followed by a success: Failed() should return true anyway569 mockT = tdutil.NewT("test")570 td.CmpTrue(t,571 tdhttp.NewTestAPI(mockT, mux).572 Get("/any").573 CmpCookies(td.Len(100)). // fails574 CmpCookies(td.Len(2)). // succeeds575 Failed())576 td.CmpContains(t, mockT.LogBuf(),577 "Failed test 'cookies should match'")578 // AutoDumpResponse579 mockT = tdutil.NewT("test")580 td.CmpTrue(t,581 tdhttp.NewTestAPI(mockT, mux).582 AutoDumpResponse().583 Get("/any/cookies").584 Name("my test").585 CmpCookies(td.Len(100)).586 Failed())587 td.CmpContains(t, mockT.LogBuf(),588 "Failed test 'my test: cookies should match'")589 td.CmpContains(t, mockT.LogBuf(), "Response.Cookie: bad length")590 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))591 // Request not sent592 mockT = tdutil.NewT("test")593 ta := tdhttp.NewTestAPI(mockT, mux).594 Name("my test").595 CmpCookies(td.Len(2))596 td.CmpTrue(t, ta.Failed())597 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")598 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")599 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")600 td.CmpNot(t, mockT.LogBuf(), td.Contains("No response received yet\n"))601 })602 t.Run("Trailer", func(t *testing.T) {603 mockT := tdutil.NewT("test")604 td.CmpFalse(t,605 tdhttp.NewTestAPI(mockT, mux).606 Get("/any").607 CmpStatus(200).608 CmpTrailer(nil). // No trailer at all609 Failed())610 mockT = tdutil.NewT("test")611 td.CmpFalse(t,612 tdhttp.NewTestAPI(mockT, mux).613 Get("/any/trailer").614 CmpStatus(200).615 CmpTrailer(containsKey).616 Failed())617 mockT = tdutil.NewT("test")618 td.CmpFalse(t,619 tdhttp.NewTestAPI(mockT, mux).620 Get("/any/trailer").621 CmpStatus(200).622 CmpTrailer(http.Header{623 "X-Testdeep-Method": {"GET"},624 "X-Testdeep-Foo": {"bar"},625 }).626 Failed())627 // AutoDumpResponse628 mockT = tdutil.NewT("test")629 td.CmpTrue(t,630 tdhttp.NewTestAPI(mockT, mux).631 AutoDumpResponse().632 Get("/any/trailer").633 Name("my test").634 CmpTrailer(http.Header{}).635 Failed())636 td.CmpContains(t, mockT.LogBuf(),637 "Failed test 'my test: trailer should match'")638 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))639 // OrDumpResponse640 mockT = tdutil.NewT("test")641 td.CmpTrue(t,642 tdhttp.NewTestAPI(mockT, mux).643 Get("/any/trailer").644 Name("my test").645 CmpTrailer(http.Header{}).646 OrDumpResponse().647 OrDumpResponse(). // only one log648 Failed())649 td.CmpContains(t, mockT.LogBuf(),650 "Failed test 'my test: trailer should match'")651 logPos := strings.Index(mockT.LogBuf(), "Received response:\n")652 if td.Cmp(t, logPos, td.Gte(0)) {653 // Only one occurrence654 td.Cmp(t,655 strings.Index(mockT.LogBuf()[logPos+1:], "Received response:\n"),656 -1)657 }658 mockT = tdutil.NewT("test")659 ta := tdhttp.NewTestAPI(mockT, mux).660 Name("my test").661 CmpTrailer(http.Header{})662 td.CmpTrue(t, ta.Failed())663 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")664 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")665 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")666 td.CmpNot(t, mockT.LogBuf(), td.Contains("No response received yet\n"))667 end := len(mockT.LogBuf())668 ta.OrDumpResponse()669 td.CmpContains(t, mockT.LogBuf()[end:], "No response received yet\n")670 })671 t.Run("Status error", func(t *testing.T) {672 mockT := tdutil.NewT("test")673 td.CmpTrue(t,674 tdhttp.NewTestAPI(mockT, mux).675 Get("/any").676 CmpStatus(400).677 Failed())678 td.CmpContains(t, mockT.LogBuf(),679 "Failed test 'status code should match'")680 // Error followed by a success: Failed() should return true anyway681 mockT = tdutil.NewT("test")682 td.CmpTrue(t,683 tdhttp.NewTestAPI(mockT, mux).684 Get("/any").685 CmpStatus(400). // fails686 CmpStatus(200). // succeeds687 Failed())688 td.CmpContains(t, mockT.LogBuf(),689 "Failed test 'status code should match'")690 mockT = tdutil.NewT("test")691 td.CmpTrue(t,692 tdhttp.NewTestAPI(mockT, mux).693 Get("/any").694 Name("my test").695 CmpStatus(400).696 Failed())697 td.CmpContains(t, mockT.LogBuf(),698 "Failed test 'my test: status code should match'")699 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))700 // AutoDumpResponse701 mockT = tdutil.NewT("test")702 td.CmpTrue(t,703 tdhttp.NewTestAPI(mockT, mux).704 AutoDumpResponse().705 Get("/any").706 Name("my test").707 CmpStatus(400).708 Failed())709 td.CmpContains(t, mockT.LogBuf(),710 "Failed test 'my test: status code should match'")711 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))712 // OrDumpResponse713 mockT = tdutil.NewT("test")714 td.CmpTrue(t,715 tdhttp.NewTestAPI(mockT, mux).716 Get("/any").717 Name("my test").718 CmpStatus(400).719 OrDumpResponse().720 OrDumpResponse(). // only one log721 Failed())722 td.CmpContains(t, mockT.LogBuf(),723 "Failed test 'my test: status code should match'")724 logPos := strings.Index(mockT.LogBuf(), "Received response:\n")725 if td.Cmp(t, logPos, td.Gte(0)) {726 // Only one occurrence727 td.Cmp(t,728 strings.Index(mockT.LogBuf()[logPos+1:], "Received response:\n"),729 -1)730 }731 mockT = tdutil.NewT("test")732 ta := tdhttp.NewTestAPI(mockT, mux).733 Name("my test").734 CmpStatus(400)735 td.CmpTrue(t, ta.Failed())736 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")737 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")738 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")739 td.CmpNot(t, mockT.LogBuf(), td.Contains("No response received yet\n"))740 end := len(mockT.LogBuf())741 ta.OrDumpResponse()742 td.CmpContains(t, mockT.LogBuf()[end:], "No response received yet\n")743 })744 t.Run("Header error", func(t *testing.T) {745 mockT := tdutil.NewT("test")746 td.CmpTrue(t,747 tdhttp.NewTestAPI(mockT, mux).748 Get("/any").749 CmpHeader(td.Not(containsKey)).750 Failed())751 td.CmpContains(t, mockT.LogBuf(),752 "Failed test 'header should match'")753 // Error followed by a success: Failed() should return true anyway754 mockT = tdutil.NewT("test")755 td.CmpTrue(t,756 tdhttp.NewTestAPI(mockT, mux).757 Get("/any").758 CmpHeader(td.Not(containsKey)). // fails759 CmpHeader(td.Ignore()). // succeeds760 Failed())761 td.CmpContains(t, mockT.LogBuf(),762 "Failed test 'header should match'")763 mockT = tdutil.NewT("test")764 td.CmpTrue(t,765 tdhttp.NewTestAPI(mockT, mux).766 Get("/any").767 Name("my test").768 CmpHeader(td.Not(containsKey)).769 Failed())770 td.CmpContains(t, mockT.LogBuf(),771 "Failed test 'my test: header should match'")772 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))773 // AutoDumpResponse774 mockT = tdutil.NewT("test")775 td.CmpTrue(t,776 tdhttp.NewTestAPI(mockT, mux).777 AutoDumpResponse().778 Get("/any").779 Name("my test").780 CmpHeader(td.Not(containsKey)).781 Failed())782 td.CmpContains(t, mockT.LogBuf(),783 "Failed test 'my test: header should match'")784 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))785 mockT = tdutil.NewT("test")786 td.CmpTrue(t,787 tdhttp.NewTestAPI(mockT, mux).788 Name("my test").789 CmpHeader(td.Not(containsKey)).790 Failed())791 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")792 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")793 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")794 })795 t.Run("Body error", func(t *testing.T) {796 mockT := tdutil.NewT("test")797 td.CmpTrue(t,798 tdhttp.NewTestAPI(mockT, mux).799 Get("/any").800 CmpBody("xxx").801 Failed())802 td.CmpContains(t, mockT.LogBuf(), "Failed test 'body contents is OK'")803 td.CmpContains(t, mockT.LogBuf(), "Response.Body: values differ\n")804 td.CmpContains(t, mockT.LogBuf(), `expected: "xxx"`)805 td.CmpContains(t, mockT.LogBuf(), `got: "GET!"`)806 // Error followed by a success: Failed() should return true anyway807 mockT = tdutil.NewT("test")808 td.CmpTrue(t,809 tdhttp.NewTestAPI(mockT, mux).810 Get("/any").811 CmpBody("xxx"). // fails812 CmpBody(td.Ignore()). // succeeds813 Failed())814 // Without AutoDumpResponse815 mockT = tdutil.NewT("test")816 td.CmpTrue(t,817 tdhttp.NewTestAPI(mockT, mux).818 Get("/any").819 Name("my test").820 CmpBody("xxx").821 Failed())822 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: body contents is OK'")823 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))824 // AutoDumpResponse825 mockT = tdutil.NewT("test")826 td.CmpTrue(t,827 tdhttp.NewTestAPI(mockT, mux).828 AutoDumpResponse().829 Get("/any").830 Name("my test").831 CmpBody("xxx").832 Failed())833 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: body contents is OK'")834 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))835 mockT = tdutil.NewT("test")836 td.CmpTrue(t,837 tdhttp.NewTestAPI(mockT, mux).838 Name("my test").839 CmpBody("xxx").840 Failed())841 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")842 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")843 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")844 // NoBody845 mockT = tdutil.NewT("test")846 td.CmpTrue(t,847 tdhttp.NewTestAPI(mockT, mux).848 Name("my test").849 NoBody().850 Failed())851 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")852 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")853 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")854 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))855 // Error followed by a success: Failed() should return true anyway856 mockT = tdutil.NewT("test")857 td.CmpTrue(t,858 tdhttp.NewTestAPI(mockT, mux).859 Name("my test").860 Head("/any").861 CmpBody("fail"). // fails862 NoBody(). // succeeds863 Failed())864 // No JSON body865 mockT = tdutil.NewT("test")866 td.CmpTrue(t,867 tdhttp.NewTestAPI(mockT, mux).868 Head("/any").869 CmpStatus(200).870 CmpHeader(containsKey).871 CmpJSONBody(json.RawMessage(`{}`)).872 Failed())873 td.CmpContains(t, mockT.LogBuf(), "Failed test 'body should not be empty'")874 td.CmpContains(t, mockT.LogBuf(), "Response body is empty!")875 td.CmpContains(t, mockT.LogBuf(), "Body cannot be empty when using CmpJSONBody")876 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))...

Full Screen

Full Screen

test_api.go

Source:test_api.go Github

copy

Full Screen

...138 }139 return ta140}141// Request sends a new HTTP request to the tested API. Any Cmp* or142// [TestAPI.NoBody] methods can now be called.143//144// Note that [TestAPI.Failed] status is reset just after this call.145func (ta *TestAPI) Request(req *http.Request) *TestAPI {146 ta.response = httptest.NewRecorder()147 ta.failed = 0148 ta.sentAt = time.Now().Truncate(0)149 ta.responseDumped = false150 ta.handler.ServeHTTP(ta.response, req)151 return ta152}153func (ta *TestAPI) checkRequestSent() bool {154 ta.t.Helper()155 // If no request has been sent, display a nice error message156 return ta.t.RootName("Request").157 Code(ta.response != nil,158 func(sent bool) error {159 if sent {160 return nil161 }162 return &ctxerr.Error{163 Message: "%% not sent!",164 Summary: ctxerr.NewSummary("A request must be sent before testing status, header, body or full response"),165 }166 },167 ta.name+"request is sent")168}169// Failed returns true if any Cmp* or [TestAPI.NoBody] method failed since last170// request sending.171func (ta *TestAPI) Failed() bool {172 return ta.failed != 0173}174// Get sends a HTTP GET to the tested API. Any Cmp* or [TestAPI.NoBody] methods175// can now be called.176//177// Note that [TestAPI.Failed] status is reset just after this call.178//179// See [NewRequest] for all possible formats accepted in headersQueryParams.180func (ta *TestAPI) Get(target string, headersQueryParams ...any) *TestAPI {181 ta.t.Helper()182 req, err := get(target, headersQueryParams...)183 if err != nil {184 ta.t.Fatal(err)185 }186 return ta.Request(req)187}188// Head sends a HTTP HEAD to the tested API. Any Cmp* or [TestAPI.NoBody] methods189// can now be called.190//191// Note that [TestAPI.Failed] status is reset just after this call.192//193// See [NewRequest] for all possible formats accepted in headersQueryParams.194func (ta *TestAPI) Head(target string, headersQueryParams ...any) *TestAPI {195 ta.t.Helper()196 req, err := head(target, headersQueryParams...)197 if err != nil {198 ta.t.Fatal(err)199 }200 return ta.Request(req)201}202// Options sends a HTTP OPTIONS to the tested API. Any Cmp* or203// [TestAPI.NoBody] methods can now be called.204//205// Note that [TestAPI.Failed] status is reset just after this call.206//207// See [NewRequest] for all possible formats accepted in headersQueryParams.208func (ta *TestAPI) Options(target string, body io.Reader, headersQueryParams ...any) *TestAPI {209 ta.t.Helper()210 req, err := options(target, body, headersQueryParams...)211 if err != nil {212 ta.t.Fatal(err)213 }214 return ta.Request(req)215}216// Post sends a HTTP POST to the tested API. Any Cmp* or217// [TestAPI.NoBody] methods can now be called.218//219// Note that [TestAPI.Failed] status is reset just after this call.220//221// See [NewRequest] for all possible formats accepted in headersQueryParams.222func (ta *TestAPI) Post(target string, body io.Reader, headersQueryParams ...any) *TestAPI {223 ta.t.Helper()224 req, err := post(target, body, headersQueryParams...)225 if err != nil {226 ta.t.Fatal(err)227 }228 return ta.Request(req)229}230// PostForm sends a HTTP POST with data's keys and values URL-encoded231// as the request body to the tested API. "Content-Type" header is232// automatically set to "application/x-www-form-urlencoded". Any Cmp*233// or [TestAPI.NoBody] methods can now be called.234//235// Note that [TestAPI.Failed] status is reset just after this call.236//237// See [NewRequest] for all possible formats accepted in headersQueryParams.238func (ta *TestAPI) PostForm(target string, data URLValuesEncoder, headersQueryParams ...any) *TestAPI {239 ta.t.Helper()240 req, err := postForm(target, data, headersQueryParams...)241 if err != nil {242 ta.t.Fatal(err)243 }244 return ta.Request(req)245}246// PostMultipartFormData sends a HTTP POST multipart request, like247// multipart/form-data one for example. See [MultipartBody] type for248// details. "Content-Type" header is automatically set depending on249// data.MediaType (defaults to "multipart/form-data") and250// data.Boundary (defaults to "go-testdeep-42"). Any Cmp* or251// [TestAPI.NoBody] methods can now be called.252//253// Note that [TestAPI.Failed] status is reset just after this call.254//255// ta.PostMultipartFormData("/data",256// &tdhttp.MultipartBody{257// // "multipart/form-data" by default258// Parts: []*tdhttp.MultipartPart{259// tdhttp.NewMultipartPartString("type", "Sales"),260// tdhttp.NewMultipartPartFile("report", "report.json", "application/json"),261// },262// },263// "X-Foo", "Foo-value",264// "X-Zip", "Zip-value",265// )266//267// See [NewRequest] for all possible formats accepted in headersQueryParams.268func (ta *TestAPI) PostMultipartFormData(target string, data *MultipartBody, headersQueryParams ...any) *TestAPI {269 ta.t.Helper()270 req, err := postMultipartFormData(target, data, headersQueryParams...)271 if err != nil {272 ta.t.Fatal(err)273 }274 return ta.Request(req)275}276// Put sends a HTTP PUT to the tested API. Any Cmp* or [TestAPI.NoBody] methods277// can now be called.278//279// Note that [TestAPI.Failed] status is reset just after this call.280//281// See [NewRequest] for all possible formats accepted in headersQueryParams.282func (ta *TestAPI) Put(target string, body io.Reader, headersQueryParams ...any) *TestAPI {283 ta.t.Helper()284 req, err := put(target, body, headersQueryParams...)285 if err != nil {286 ta.t.Fatal(err)287 }288 return ta.Request(req)289}290// Patch sends a HTTP PATCH to the tested API. Any Cmp* or [TestAPI.NoBody] methods291// can now be called.292//293// Note that [TestAPI.Failed] status is reset just after this call.294//295// See [NewRequest] for all possible formats accepted in headersQueryParams.296func (ta *TestAPI) Patch(target string, body io.Reader, headersQueryParams ...any) *TestAPI {297 ta.t.Helper()298 req, err := patch(target, body, headersQueryParams...)299 if err != nil {300 ta.t.Fatal(err)301 }302 return ta.Request(req)303}304// Delete sends a HTTP DELETE to the tested API. Any Cmp* or [TestAPI.NoBody] methods305// can now be called.306//307// Note that [TestAPI.Failed] status is reset just after this call.308//309// See [NewRequest] for all possible formats accepted in headersQueryParams.310func (ta *TestAPI) Delete(target string, body io.Reader, headersQueryParams ...any) *TestAPI {311 ta.t.Helper()312 req, err := del(target, body, headersQueryParams...)313 if err != nil {314 ta.t.Fatal(err)315 }316 return ta.Request(req)317}318// NewJSONRequest sends a HTTP request with body marshaled to319// JSON. "Content-Type" header is automatically set to320// "application/json". Any Cmp* or [TestAPI.NoBody] methods can now be called.321//322// Note that [TestAPI.Failed] status is reset just after this call.323//324// See [NewRequest] for all possible formats accepted in headersQueryParams.325func (ta *TestAPI) NewJSONRequest(method, target string, body any, headersQueryParams ...any) *TestAPI {326 ta.t.Helper()327 req, err := newJSONRequest(method, target, body, headersQueryParams...)328 if err != nil {329 ta.t.Fatal(err)330 }331 return ta.Request(req)332}333// PostJSON sends a HTTP POST with body marshaled to334// JSON. "Content-Type" header is automatically set to335// "application/json". Any Cmp* or [TestAPI.NoBody] methods can now be called.336//337// Note that [TestAPI.Failed] status is reset just after this call.338//339// See [NewRequest] for all possible formats accepted in headersQueryParams.340func (ta *TestAPI) PostJSON(target string, body any, headersQueryParams ...any) *TestAPI {341 ta.t.Helper()342 req, err := newJSONRequest(http.MethodPost, target, body, headersQueryParams...)343 if err != nil {344 ta.t.Fatal(err)345 }346 return ta.Request(req)347}348// PutJSON sends a HTTP PUT with body marshaled to349// JSON. "Content-Type" header is automatically set to350// "application/json". Any Cmp* or [TestAPI.NoBody] methods can now be called.351//352// Note that [TestAPI.Failed] status is reset just after this call.353//354// See [NewRequest] for all possible formats accepted in headersQueryParams.355func (ta *TestAPI) PutJSON(target string, body any, headersQueryParams ...any) *TestAPI {356 ta.t.Helper()357 req, err := newJSONRequest(http.MethodPut, target, body, headersQueryParams...)358 if err != nil {359 ta.t.Fatal(err)360 }361 return ta.Request(req)362}363// PatchJSON sends a HTTP PATCH with body marshaled to364// JSON. "Content-Type" header is automatically set to365// "application/json". Any Cmp* or [TestAPI.NoBody] methods can now be called.366//367// Note that [TestAPI.Failed] status is reset just after this call.368//369// See [NewRequest] for all possible formats accepted in headersQueryParams.370func (ta *TestAPI) PatchJSON(target string, body any, headersQueryParams ...any) *TestAPI {371 ta.t.Helper()372 req, err := newJSONRequest(http.MethodPatch, target, body, headersQueryParams...)373 if err != nil {374 ta.t.Fatal(err)375 }376 return ta.Request(req)377}378// DeleteJSON sends a HTTP DELETE with body marshaled to379// JSON. "Content-Type" header is automatically set to380// "application/json". Any Cmp* or [TestAPI.NoBody] methods can now be called.381//382// Note that [TestAPI.Failed] status is reset just after this call.383//384// See [NewRequest] for all possible formats accepted in headersQueryParams.385func (ta *TestAPI) DeleteJSON(target string, body any, headersQueryParams ...any) *TestAPI {386 ta.t.Helper()387 req, err := newJSONRequest(http.MethodDelete, target, body, headersQueryParams...)388 if err != nil {389 ta.t.Fatal(err)390 }391 return ta.Request(req)392}393// NewXMLRequest sends a HTTP request with body marshaled to394// XML. "Content-Type" header is automatically set to395// "application/xml". Any Cmp* or [TestAPI.NoBody] methods can now be called.396//397// Note that [TestAPI.Failed] status is reset just after this call.398//399// See [NewRequest] for all possible formats accepted in headersQueryParams.400func (ta *TestAPI) NewXMLRequest(method, target string, body any, headersQueryParams ...any) *TestAPI {401 ta.t.Helper()402 req, err := newXMLRequest(method, target, body, headersQueryParams...)403 if err != nil {404 ta.t.Fatal(err)405 }406 return ta.Request(req)407}408// PostXML sends a HTTP POST with body marshaled to409// XML. "Content-Type" header is automatically set to410// "application/xml". Any Cmp* or [TestAPI.NoBody] methods can now be called.411//412// Note that [TestAPI.Failed] status is reset just after this call.413//414// See [NewRequest] for all possible formats accepted in headersQueryParams.415func (ta *TestAPI) PostXML(target string, body any, headersQueryParams ...any) *TestAPI {416 ta.t.Helper()417 req, err := newXMLRequest(http.MethodPost, target, body, headersQueryParams...)418 if err != nil {419 ta.t.Fatal(err)420 }421 return ta.Request(req)422}423// PutXML sends a HTTP PUT with body marshaled to424// XML. "Content-Type" header is automatically set to425// "application/xml". Any Cmp* or [TestAPI.NoBody] methods can now be called.426//427// Note that [TestAPI.Failed] status is reset just after this call.428//429// See [NewRequest] for all possible formats accepted in headersQueryParams.430func (ta *TestAPI) PutXML(target string, body any, headersQueryParams ...any) *TestAPI {431 ta.t.Helper()432 req, err := newXMLRequest(http.MethodPut, target, body, headersQueryParams...)433 if err != nil {434 ta.t.Fatal(err)435 }436 return ta.Request(req)437}438// PatchXML sends a HTTP PATCH with body marshaled to439// XML. "Content-Type" header is automatically set to440// "application/xml". Any Cmp* or [TestAPI.NoBody] methods can now be called.441//442// Note that [TestAPI.Failed] status is reset just after this call.443//444// See [NewRequest] for all possible formats accepted in headersQueryParams.445func (ta *TestAPI) PatchXML(target string, body any, headersQueryParams ...any) *TestAPI {446 ta.t.Helper()447 req, err := newXMLRequest(http.MethodPatch, target, body, headersQueryParams...)448 if err != nil {449 ta.t.Fatal(err)450 }451 return ta.Request(req)452}453// DeleteXML sends a HTTP DELETE with body marshaled to454// XML. "Content-Type" header is automatically set to455// "application/xml". Any Cmp* or [TestAPI.NoBody] methods can now be called.456//457// Note that [TestAPI.Failed] status is reset just after this call.458//459// See [NewRequest] for all possible formats accepted in headersQueryParams.460func (ta *TestAPI) DeleteXML(target string, body any, headersQueryParams ...any) *TestAPI {461 ta.t.Helper()462 req, err := newXMLRequest(http.MethodDelete, target, body, headersQueryParams...)463 if err != nil {464 ta.t.Fatal(err)465 }466 return ta.Request(req)467}468// CmpResponse tests the last request response status against469// expectedResponse. expectedResponse can be a *http.Response or more470// probably a [td.TestDeep] operator.471//472// ta := tdhttp.NewTestAPI(t, mux)473//474// ta.Get("/test").475// CmpResponse(td.Struct(476// &http.Response{Status: http.StatusOK}, td.StructFields{477// "Header": td.SuperMapOf(http.Header{"X-Test": {"pipo"}}),478// "ContentLength": td.Gt(10),479// }))480//481// Some tests can be hard to achieve using operators chaining. In this482// case, the [td.Code] operator can be used to take the full control483// over the extractions and comparisons to do:484//485// ta.Get("/test").486// CmpResponse(td.Code(func (assert, require *td.T, r *http.Response) {487// token, err := ParseToken(r.Header.Get("X-Token"))488// require.CmpNoError(err)489//490// baseURL,err := url.Parse(r.Header.Get("X-Base-URL"))491// require.CmpNoError(err)492//493// assert.Cmp(baseURL.Query().Get("id"), token.ID)494// }))495//496// It fails if no request has been sent yet.497func (ta *TestAPI) CmpResponse(expectedResponse any) *TestAPI {498 defer ta.t.AnchorsPersistTemporarily()()499 ta.t.Helper()500 if !ta.checkRequestSent() {501 ta.failed |= responseFailed502 return ta503 }504 if !ta.t.RootName("Response").505 Cmp(ta.response.Result(), expectedResponse, ta.name+"full response should match") {506 ta.failed |= responseFailed507 if ta.autoDumpResponse {508 ta.dumpResponse()509 }510 }511 return ta512}513// CmpStatus tests the last request response status against514// expectedStatus. expectedStatus can be an int to match a fixed HTTP515// status code, or a [td.TestDeep] operator.516//517// ta := tdhttp.NewTestAPI(t, mux)518//519// ta.Get("/test").520// CmpStatus(http.StatusOK)521//522// ta.PostJSON("/new", map[string]string{"name": "Bob"}).523// CmpStatus(td.Between(200, 202))524//525// It fails if no request has been sent yet.526func (ta *TestAPI) CmpStatus(expectedStatus any) *TestAPI {527 defer ta.t.AnchorsPersistTemporarily()()528 ta.t.Helper()529 if !ta.checkRequestSent() {530 ta.failed |= statusFailed531 return ta532 }533 if !ta.t.RootName("Response.Status").534 CmpLax(ta.response.Code, expectedStatus, ta.name+"status code should match") {535 ta.failed |= statusFailed536 if ta.autoDumpResponse {537 ta.dumpResponse()538 }539 }540 return ta541}542// CmpHeader tests the last request response header against543// expectedHeader. expectedHeader can be a [http.Header] or a544// [td.TestDeep] operator. Keep in mind that if it is a [http.Header],545// it has to match exactly the response header. Often only the546// presence of a header key is needed:547//548// ta := tdhttp.NewTestAPI(t, mux).549// PostJSON("/new", map[string]string{"name": "Bob"}).550// CmdStatus(201).551// CmpHeader(td.ContainsKey("X-Custom"))552//553// or some specific key, value pairs:554//555// ta.CmpHeader(td.SuperMapOf(556// http.Header{557// "X-Account": []string{"Bob"},558// },559// td.MapEntries{560// "X-Token": td.Bag(td.Re(`^[a-z0-9-]{32}\z`)),561// }),562// )563//564// Note that CmpHeader calls can be chained:565//566// ta.CmpHeader(td.ContainsKey("X-Account")).567// CmpHeader(td.ContainsKey("X-Token"))568//569// instead of doing all tests in one call as [td.All] operator allows it:570//571// ta.CmpHeader(td.All(572// td.ContainsKey("X-Account"),573// td.ContainsKey("X-Token"),574// ))575//576// It fails if no request has been sent yet.577func (ta *TestAPI) CmpHeader(expectedHeader any) *TestAPI {578 defer ta.t.AnchorsPersistTemporarily()()579 ta.t.Helper()580 if !ta.checkRequestSent() {581 ta.failed |= headerFailed582 return ta583 }584 if !ta.t.RootName("Response.Header").585 CmpLax(ta.response.Result().Header, expectedHeader, ta.name+"header should match") {586 ta.failed |= headerFailed587 if ta.autoDumpResponse {588 ta.dumpResponse()589 }590 }591 return ta592}593// CmpTrailer tests the last request response trailer against594// expectedTrailer. expectedTrailer can be a [http.Header] or a595// [td.TestDeep] operator. Keep in mind that if it is a [http.Header],596// it has to match exactly the response trailer. Often only the597// presence of a trailer key is needed:598//599// ta := tdhttp.NewTestAPI(t, mux).600// PostJSON("/new", map[string]string{"name": "Bob"}).601// CmdStatus(201).602// CmpTrailer(td.ContainsKey("X-Custom"))603//604// or some specific key, value pairs:605//606// ta.CmpTrailer(td.SuperMapOf(607// http.Header{608// "X-Account": []string{"Bob"},609// },610// td.MapEntries{611// "X-Token": td.Re(`^[a-z0-9-]{32}\z`),612// }),613// )614//615// Note that CmpTrailer calls can be chained:616//617// ta.CmpTrailer(td.ContainsKey("X-Account")).618// CmpTrailer(td.ContainsKey("X-Token"))619//620// instead of doing all tests in one call as [td.All] operator allows it:621//622// ta.CmpTrailer(td.All(623// td.ContainsKey("X-Account"),624// td.ContainsKey("X-Token"),625// ))626//627// It fails if no request has been sent yet.628//629// Note that until go1.19, it does not handle multiple values in630// a single Trailer header field.631func (ta *TestAPI) CmpTrailer(expectedTrailer any) *TestAPI {632 defer ta.t.AnchorsPersistTemporarily()()633 ta.t.Helper()634 if !ta.checkRequestSent() {635 ta.failed |= trailerFailed636 return ta637 }638 if !ta.t.RootName("Response.Trailer").639 CmpLax(ta.response.Result().Trailer, expectedTrailer, ta.name+"trailer should match") {640 ta.failed |= trailerFailed641 if ta.autoDumpResponse {642 ta.dumpResponse()643 }644 }645 return ta646}647// CmpCookies tests the last request response cookies against648// expectedCookies. expectedCookies can be a [][*http.Cookie] or a649// [td.TestDeep] operator. Keep in mind that if it is a650// [][*http.Cookie], it has to match exactly the response651// cookies. Often only the presence of a cookie key is needed:652//653// ta := tdhttp.NewTestAPI(t, mux).654// PostJSON("/login", map[string]string{"name": "Bob", "password": "Sponge"}).655// CmdStatus(200).656// CmpCookies(td.SuperBagOf(td.Struct(&http.Cookie{Name: "cookie_session"}, nil))).657// CmpCookies(td.SuperBagOf(td.Smuggle("Name", "cookie_session"))) // shorter658//659// To make tests easier, [http.Cookie.Raw] and [http.Cookie.RawExpires] fields660// of each [*http.Cookie] are zeroed before doing the comparison. So no need661// to fill them when comparing against a simple literal as in:662//663// ta := tdhttp.NewTestAPI(t, mux).664// PostJSON("/login", map[string]string{"name": "Bob", "password": "Sponge"}).665// CmdStatus(200).666// CmpCookies([]*http.Cookies{667// {Name: "cookieName1", Value: "cookieValue1"},668// {Name: "cookieName2", Value: "cookieValue2"},669// })670//671// It fails if no request has been sent yet.672func (ta *TestAPI) CmpCookies(expectedCookies any) *TestAPI {673 defer ta.t.AnchorsPersistTemporarily()()674 ta.t.Helper()675 if !ta.checkRequestSent() {676 ta.failed |= cookiesFailed677 return ta678 }679 // Empty Raw* fields to make comparisons easier680 cookies := ta.response.Result().Cookies()681 for _, c := range cookies {682 c.RawExpires, c.Raw = "", ""683 }684 if !ta.t.RootName("Response.Cookie").685 CmpLax(cookies, expectedCookies, ta.name+"cookies should match") {686 ta.failed |= cookiesFailed687 if ta.autoDumpResponse {688 ta.dumpResponse()689 }690 }691 return ta692}693// findCmpXBodyCaller finds the oldest Cmp* method called.694func findCmpXBodyCaller() string {695 var (696 fn string697 pc [20]uintptr698 found bool699 )700 if num := runtime.Callers(5, pc[:]); num > 0 {701 frames := runtime.CallersFrames(pc[:num])702 for {703 frame, more := frames.Next()704 if pos := strings.Index(frame.Function, "tdhttp.(*TestAPI).Cmp"); pos > 0 {705 fn = frame.Function[pos+18:]706 found = true707 } else if found {708 more = false709 }710 if !more {711 break712 }713 }714 }715 return fn716}717func (ta *TestAPI) cmpMarshaledBody(718 acceptEmptyBody bool,719 unmarshal func([]byte, any) error,720 expectedBody any,721) *TestAPI {722 defer ta.t.AnchorsPersistTemporarily()()723 ta.t.Helper()724 if !ta.checkRequestSent() {725 ta.failed |= bodyFailed726 return ta727 }728 if !acceptEmptyBody &&729 !ta.t.RootName("Response body").Code(ta.response.Body.Bytes(),730 func(b []byte) error {731 if len(b) > 0 {732 return nil733 }734 return &ctxerr.Error{735 Message: "%% is empty!",736 Summary: ctxerr.NewSummary(737 "Body cannot be empty when using " + findCmpXBodyCaller()),738 }739 },740 ta.name+"body should not be empty") {741 ta.failed |= bodyFailed742 if ta.autoDumpResponse {743 ta.dumpResponse()744 }745 return ta746 }747 tt := ta.t.RootName("Response.Body")748 var bodyType reflect.Type749 // If expectedBody is a TestDeep operator, try to ask it the type750 // behind it. It should work in most cases (typically Struct(),751 // Map() & Slice()).752 var unknownExpectedType, showRawBody bool753 op, ok := expectedBody.(td.TestDeep)754 if ok {755 bodyType = op.TypeBehind()756 if bodyType == nil {757 // As the expected body type cannot be guessed, try to758 // unmarshal in an any759 bodyType = types.Interface760 unknownExpectedType = true761 // Special case for Ignore & NotEmpty operators762 switch op.GetLocation().Func {763 case "Ignore", "NotEmpty":764 showRawBody = (ta.failed & statusFailed) != 0 // Show real body if status failed765 }766 }767 } else {768 bodyType = reflect.TypeOf(expectedBody)769 if bodyType == nil {770 bodyType = types.Interface771 }772 }773 // For unmarshaling below, body must be a pointer774 bodyPtr := reflect.New(bodyType)775 // Try to unmarshal body776 if !tt.RootName("unmarshal(Response.Body)").777 CmpNoError(unmarshal(ta.response.Body.Bytes(), bodyPtr.Interface()), ta.name+"body unmarshaling") {778 // If unmarshal failed, perhaps it's coz the expected body type779 // is unknown?780 if unknownExpectedType {781 tt.Logf("Cannot guess the body expected type as %[1]s TestDeep\n"+782 "operator does not know the type behind it.\n"+783 "You can try All(Isa(EXPECTED_TYPE), %[1]s(…)) to disambiguate…",784 op.GetLocation().Func)785 }786 showRawBody = true // let's show its real body contents787 ta.failed |= bodyFailed788 } else if !tt.Cmp(bodyPtr.Elem().Interface(), expectedBody, ta.name+"body contents is OK") {789 // Try to catch bad body expected type when nothing has been set790 // to non-zero during unmarshaling body. In this case, require791 // to show raw body contents.792 if len(ta.response.Body.Bytes()) > 0 &&793 td.EqDeeply(bodyPtr.Interface(), reflect.New(bodyType).Interface()) {794 showRawBody = true795 tt.Log("Hmm… It seems nothing has been set during unmarshaling…")796 }797 ta.failed |= bodyFailed798 }799 if showRawBody || ((ta.failed&bodyFailed) != 0 && ta.autoDumpResponse) {800 ta.dumpResponse()801 }802 return ta803}804// CmpMarshaledBody tests that the last request response body can be805// unmarshaled using unmarshal function and then, that it matches806// expectedBody. expectedBody can be any type unmarshal function can807// handle, or a [td.TestDeep] operator.808//809// See [TestAPI.CmpJSONBody] and [TestAPI.CmpXMLBody] sources for810// examples of use.811//812// It fails if no request has been sent yet.813func (ta *TestAPI) CmpMarshaledBody(unmarshal func([]byte, any) error, expectedBody any) *TestAPI {814 ta.t.Helper()815 return ta.cmpMarshaledBody(false, unmarshal, expectedBody)816}817// CmpBody tests the last request response body against818// expectedBody. expectedBody can be a []byte, a string or a819// [td.TestDeep] operator.820//821// ta := tdhttp.NewTestAPI(t, mux)822//823// ta.Get("/test").824// CmpStatus(http.StatusOK).825// CmpBody("OK!\n")826//827// ta.Get("/test").828// CmpStatus(http.StatusOK).829// CmpBody(td.Contains("OK"))830//831// It fails if no request has been sent yet.832func (ta *TestAPI) CmpBody(expectedBody any) *TestAPI {833 ta.t.Helper()834 if expectedBody == nil {835 return ta.NoBody()836 }837 return ta.cmpMarshaledBody(838 true, // accept empty body839 func(body []byte, target any) error {840 switch target := target.(type) {841 case *string:842 *target = string(body)843 case *[]byte:844 *target = body845 case *any:846 *target = body847 default:848 // cmpMarshaledBody always calls us with target as a pointer849 return fmt.Errorf(850 "CmpBody only accepts expectedBody be a []byte, a string or a TestDeep operator allowing to match these types, but not type %s",851 reflect.TypeOf(target).Elem())852 }853 return nil854 },855 expectedBody)856}857// CmpJSONBody tests that the last request response body can be858// [json.Unmarshal]'ed and that it matches expectedBody. expectedBody859// can be any type one can [json.Unmarshal] into, or a [td.TestDeep]860// operator.861//862// ta := tdhttp.NewTestAPI(t, mux)863//864// ta.Get("/person/42").865// CmpStatus(http.StatusOK).866// CmpJSONBody(Person{867// ID: 42,868// Name: "Bob",869// Age: 26,870// })871//872// ta.PostJSON("/person", Person{Name: "Bob", Age: 23}).873// CmpStatus(http.StatusCreated).874// CmpJSONBody(td.SStruct(875// Person{876// Name: "Bob",877// Age: 26,878// },879// td.StructFields{880// "ID": td.NotZero(),881// }))882//883// The same with anchoring, and so without [td.SStruct]:884//885// ta := tdhttp.NewTestAPI(tt, mux)886//887// ta.PostJSON("/person", Person{Name: "Bob", Age: 23}).888// CmpStatus(http.StatusCreated).889// CmpJSONBody(Person{890// ID: ta.Anchor(td.NotZero(), uint64(0)).(uint64),891// Name: "Bob",892// Age: 26,893// })894//895// The same using [td.JSON]:896//897// ta.PostJSON("/person", Person{Name: "Bob", Age: 23}).898// CmpStatus(http.StatusCreated).899// CmpJSONBody(td.JSON(`900// {901// "id": NotZero(),902// "name": "Bob",903// "age": 26904// }`))905//906// It fails if no request has been sent yet.907func (ta *TestAPI) CmpJSONBody(expectedBody any) *TestAPI {908 ta.t.Helper()909 return ta.CmpMarshaledBody(json.Unmarshal, expectedBody)910}911// CmpXMLBody tests that the last request response body can be912// [xml.Unmarshal]'ed and that it matches expectedBody. expectedBody913// can be any type one can [xml.Unmarshal] into, or a [td.TestDeep]914// operator.915//916// ta := tdhttp.NewTestAPI(t, mux)917//918// ta.Get("/person/42").919// CmpStatus(http.StatusOK).920// CmpXMLBody(Person{921// ID: 42,922// Name: "Bob",923// Age: 26,924// })925//926// ta.Get("/person/43").927// CmpStatus(http.StatusOK).928// CmpXMLBody(td.SStruct(929// Person{930// Name: "Bob",931// Age: 26,932// },933// td.StructFields{934// "ID": td.NotZero(),935// }))936//937// The same with anchoring:938//939// ta := tdhttp.NewTestAPI(tt, mux)940//941// ta.Get("/person/42").942// CmpStatus(http.StatusOK).943// CmpXMLBody(Person{944// ID: ta.Anchor(td.NotZero(), uint64(0)).(uint64),945// Name: "Bob",946// Age: 26,947// })948//949// It fails if no request has been sent yet.950func (ta *TestAPI) CmpXMLBody(expectedBody any) *TestAPI {951 ta.t.Helper()952 return ta.CmpMarshaledBody(xml.Unmarshal, expectedBody)953}954// NoBody tests that the last request response body is empty.955//956// It fails if no request has been sent yet.957func (ta *TestAPI) NoBody() *TestAPI {958 defer ta.t.AnchorsPersistTemporarily()()959 ta.t.Helper()960 if !ta.checkRequestSent() {961 ta.failed |= bodyFailed962 return ta963 }964 ok := ta.t.RootName("Response.Body").965 Code(len(ta.response.Body.Bytes()) == 0,966 func(empty bool) error {967 if empty {968 return nil969 }970 return &ctxerr.Error{971 Message: "%% is not empty",...

Full Screen

Full Screen

multipart_test.go

Source:multipart_test.go Github

copy

Full Screen

1// Copyright (c) 2021, Maxime Soulé2// All rights reserved.3//4// This source code is licensed under the BSD-style license found in the5// LICENSE file in the root directory of this source tree.6package tdhttp_test7import (8 "bytes"9 "io"10 "mime/multipart"11 "net/http"12 "os"13 "path/filepath"14 "strings"15 "testing"16 "github.com/maxatome/go-testdeep/helpers/tdhttp"17 "github.com/maxatome/go-testdeep/td"18)19func TestMultipartPart(t *testing.T) {20 assert, require := td.AssertRequire(t)21 check := func(part *tdhttp.MultipartPart, expected string) {22 t.Helper()23 var final bytes.Buffer24 // Read in 2 times to be sure Read() can be called several times25 _, err := io.CopyN(&final, part, 5)26 if assert.CmpNoError(err) {27 _, err := io.Copy(&final, part)28 if assert.CmpNoError(err) {29 assert.Cmp(final.String(), strings.ReplaceAll(expected, "%CR", "\r"))30 }31 }32 }33 // Full empty34 b, err := io.ReadAll(&tdhttp.MultipartPart{})35 assert.CmpNoError(err)36 assert.Len(b, 0)37 // Without name38 part := tdhttp.MultipartPart{39 Content: strings.NewReader("hey!\nyo!"),40 }41 check(&part, `Content-Type: text/plain; charset=utf-8%CR42%CR43hey!44yo!`)45 // Without body46 part = tdhttp.MultipartPart{47 Name: "nobody",48 }49 check(&part, `Content-Disposition: form-data; name="nobody"%CR50`)51 // Without header52 part = tdhttp.MultipartPart{53 Name: "pipo",54 Content: strings.NewReader("hey!\nyo!"),55 }56 check(&part, `Content-Disposition: form-data; name="pipo"%CR57Content-Type: text/plain; charset=utf-8%CR58%CR59hey!60yo!`)61 // With header62 part = tdhttp.MultipartPart{63 Name: "pipo",64 Content: strings.NewReader("hey!\nyo!"),65 Header: http.Header{66 "Pipo": []string{"bingo"},67 "Content-Type": []string{"text/rococo; charset=utf-8"},68 },69 }70 check(&part, `Content-Disposition: form-data; name="pipo"%CR71Content-Type: text/rococo; charset=utf-8%CR72Pipo: bingo%CR73%CR74hey!75yo!`)76 // Without name & body, but with header77 part = tdhttp.MultipartPart{78 Header: http.Header{79 "Pipo": []string{"bingo"},80 },81 }82 check(&part, `Pipo: bingo%CR83`)84 // io.Reader85 check(tdhttp.NewMultipartPart("io", strings.NewReader("hey!\nyo!")),86 `Content-Disposition: form-data; name="io"%CR87Content-Type: text/plain; charset=utf-8%CR88%CR89hey!90yo!`)91 // io.Reader + Content-Type92 check(tdhttp.NewMultipartPart("io", strings.NewReader("hey!\nyo!"), "text/rococo; charset=utf-8"),93 `Content-Disposition: form-data; name="io"%CR94Content-Type: text/rococo; charset=utf-8%CR95%CR96hey!97yo!`)98 // String99 check(tdhttp.NewMultipartPartString("pipo", "hey!\nyo!"),100 `Content-Disposition: form-data; name="pipo"%CR101Content-Type: text/plain; charset=utf-8%CR102%CR103hey!104yo!`)105 // String + Content-Type106 check(tdhttp.NewMultipartPartString("pipo", "hey!\nyo!", "text/rococo; charset=utf-8"),107 `Content-Disposition: form-data; name="pipo"%CR108Content-Type: text/rococo; charset=utf-8%CR109%CR110hey!111yo!`)112 // Bytes113 check(tdhttp.NewMultipartPartBytes("pipo", []byte("hey!\nyo!")),114 `Content-Disposition: form-data; name="pipo"%CR115Content-Type: text/plain; charset=utf-8%CR116%CR117hey!118yo!`)119 // Bytes + Content-Type120 check(tdhttp.NewMultipartPartBytes("pipo", []byte("hey!\nyo!"), "text/rococo; charset=utf-8"),121 `Content-Disposition: form-data; name="pipo"%CR122Content-Type: text/rococo; charset=utf-8%CR123%CR124hey!125yo!`)126 // With file name127 dir, err := os.MkdirTemp("", "multipart")128 require.CmpNoError(err)129 defer os.RemoveAll(dir)130 filePath := filepath.Join(dir, "body.txt")131 require.CmpNoError(os.WriteFile(filePath, []byte("hey!\nyo!"), 0666))132 check(tdhttp.NewMultipartPartFile("pipo", filePath),133 `Content-Disposition: form-data; name="pipo"; filename="body.txt"%CR134Content-Type: text/plain; charset=utf-8%CR135%CR136hey!137yo!`)138 // With file name + Content-Type139 check(tdhttp.NewMultipartPartFile("pipo", filePath, "text/rococo; charset=utf-8"),140 `Content-Disposition: form-data; name="pipo"; filename="body.txt"%CR141Content-Type: text/rococo; charset=utf-8%CR142%CR143hey!144yo!`)145 // Error during os.Open146 _, err = io.ReadAll(147 tdhttp.NewMultipartPartFile("pipo", filepath.Join(dir, "unknown.xxx")),148 )149 assert.CmpError(err)150}151func TestMultipartBody(t *testing.T) {152 assert, require := td.AssertRequire(t)153 dir, err := os.MkdirTemp("", "multipart")154 require.CmpNoError(err)155 defer os.RemoveAll(dir)156 filePath := filepath.Join(dir, "body.txt")157 require.CmpNoError(os.WriteFile(filePath, []byte("hey!\nyo!"), 0666))158 for _, boundary := range []struct{ in, out string }{159 {in: "", out: "go-testdeep-42"},160 {in: "BoUnDaRy", out: "BoUnDaRy"},161 } {162 multi := tdhttp.MultipartBody{163 Boundary: boundary.in,164 Parts: []*tdhttp.MultipartPart{165 {166 Name: "pipo",167 Content: strings.NewReader("pipo!\nbingo!"),168 },169 tdhttp.NewMultipartPartFile("file", filePath),170 tdhttp.NewMultipartPartString("string", "zip!\nzap!"),171 tdhttp.NewMultipartPartBytes("bytes", []byte(`{"ola":"hello"}`), "application/json"),172 tdhttp.NewMultipartPart("io", nil),173 tdhttp.NewMultipartPart("", nil),174 },175 }176 expected := `--` + boundary.out + `%CR177Content-Disposition: form-data; name="pipo"%CR178Content-Type: text/plain; charset=utf-8%CR179%CR180pipo!181bingo!%CR182--` + boundary.out + `%CR183Content-Disposition: form-data; name="file"; filename="body.txt"%CR184Content-Type: text/plain; charset=utf-8%CR185%CR186hey!187yo!%CR188--` + boundary.out + `%CR189Content-Disposition: form-data; name="string"%CR190Content-Type: text/plain; charset=utf-8%CR191%CR192zip!193zap!%CR194--` + boundary.out + `%CR195Content-Disposition: form-data; name="bytes"%CR196Content-Type: application/json%CR197%CR198{"ola":"hello"}%CR199--` + boundary.out + `%CR200Content-Disposition: form-data; name="io"%CR201%CR202--` + boundary.out + `%CR203%CR204--` + boundary.out + `--%CR205`206 var final bytes.Buffer207 // Read in 2 times to be sure Read() can be called several times208 _, err = io.CopyN(&final, &multi, 10)209 if !assert.CmpNoError(err) {210 continue211 }212 _, err := io.Copy(&final, &multi)213 if !assert.CmpNoError(err) {214 continue215 }216 if !assert.Cmp(final.String(), strings.ReplaceAll(expected, "%CR", "\r")) {217 continue218 }219 rd := multipart.NewReader(&final, boundary.out)220 // 0221 part, err := rd.NextPart()222 if assert.CmpNoError(err) {223 assert.Cmp(part.FormName(), "pipo")224 assert.Cmp(part.FileName(), "")225 assert.Smuggle(part, io.ReadAll, td.String("pipo!\nbingo!"))226 }227 // 1228 part, err = rd.NextPart()229 if assert.CmpNoError(err) {230 assert.Cmp(part.FormName(), "file")231 assert.Cmp(part.FileName(), "body.txt")232 assert.Smuggle(part, io.ReadAll, td.String("hey!\nyo!"))233 }234 // 2235 part, err = rd.NextPart()236 if assert.CmpNoError(err) {237 assert.Cmp(part.FormName(), "string")238 assert.Cmp(part.FileName(), "")239 assert.Smuggle(part, io.ReadAll, td.String("zip!\nzap!"))240 }241 // 3242 part, err = rd.NextPart()243 if assert.CmpNoError(err) {244 assert.Cmp(part.FormName(), "bytes")245 assert.Cmp(part.FileName(), "")246 assert.Smuggle(part, io.ReadAll, td.String(`{"ola":"hello"}`))247 }248 // 4249 part, err = rd.NextPart()250 if assert.CmpNoError(err) {251 assert.Cmp(part.FormName(), "io")252 assert.Cmp(part.FileName(), "")253 assert.Smuggle(part, io.ReadAll, td.String(""))254 }255 // 5256 part, err = rd.NextPart()257 if assert.CmpNoError(err) {258 assert.Cmp(part.FormName(), "")259 assert.Cmp(part.FileName(), "")260 assert.Smuggle(part, io.ReadAll, td.String(""))261 }262 // EOF263 _, err = rd.NextPart()264 assert.Cmp(err, io.EOF)265 }266 multi := tdhttp.MultipartBody{}267 td.Cmp(t, multi.ContentType(), `multipart/form-data; boundary="go-testdeep-42"`)268 td.Cmp(t, multi.Boundary, "go-testdeep-42",269 "Boundary field set with default value")270 td.CmpEmpty(t, multi.MediaType, "MediaType field NOT set")271 multi.Boundary = "BoUnDaRy"272 td.Cmp(t, multi.ContentType(), `multipart/form-data; boundary="BoUnDaRy"`)273 multi.MediaType = "multipart/mixed"274 td.Cmp(t, multi.ContentType(), `multipart/mixed; boundary="BoUnDaRy"`)275}...

Full Screen

Full Screen

NoBody

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 if err != nil {4 panic(err)5 }6 defer resp.Body.Close()7 buf := buffer.New(resp.Body)8 doc, err := html.Parse(buf)9 if err != nil {10 panic(err)11 }12 fmt.Println(tdhttp.NoBody(doc))13}

Full Screen

Full Screen

NoBody

Using AI Code Generation

copy

Full Screen

1import (2func main() {3Server: Apache/2.4.18 (Ubuntu)4 r.Init(parse.NewInputString(input))5 t.Init(&r)6 for {7 tt := t.Next()8 if tt == html.ErrorToken {9 }10 fmt.Println(tt, string(t.Text()))11 }12}13Header Server Apache/2.4.18 (Ubuntu)14import (15func main() {16Server: Apache/2.4.18 (Ubuntu)17 r.Init(parse.NewInputString(input))18 t.Init(&r)19 for {

Full Screen

Full Screen

NoBody

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 m := minify.New()4 m.AddFunc("text/javascript", js.Minify)5 m.AddFunc("application/json", json.Minify)6 m.AddFunc("text/xml", xml.Minify)7 m.AddFunc("text/css", css.Minify)8 m.AddFunc("text/html", html.Minify)9 minified, err := m.Bytes("text/javascript", []byte("var foo = function() {};"))10 if err != nil {11 panic(err)12 }13 fmt.Println(string(minified))14}15import (

Full Screen

Full Screen

NoBody

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 if err != nil {4 panic(err)5 }6 b := buffer.New(nil)7 err = tdhttp.NoBody(b, req)8 if err != nil {9 panic(err)10 }11 fmt.Println(b.String())12 if err != nil {13 panic(err)14 }15 b = buffer.New(nil)16 err = tdhttp.NoBody(b, req)17 if err != nil {18 panic(err)19 }20 fmt.Println(b.String())21 res := http.Response{22 Header: http.Header{},23 }24 b = buffer.New(nil)25 err = tdhttp.NoBody(b, &res)26 if err != nil {27 panic(err)28 }29 fmt.Println(b.String())30 res = http.Response{31 Header: http.Header{},32 }33 b = buffer.New(nil)34 err = tdhttp.NoBody(b, &res)35 if err != nil {36 panic(err)37 }38 fmt.Println(b.String())39 res = http.Response{

Full Screen

Full Screen

NoBody

Using AI Code Generation

copy

Full Screen

1func main() {2 tdhttp.NoBody()3}4func main() {5 tdhttp.NoBody()6}

Full Screen

Full Screen

NoBody

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 if err != nil {4 fmt.Println(err)5 }6}7import (8func main() {9 if err != nil {10 fmt.Println(err)11 }12}13import (14func main() {15 if err != nil {16 fmt.Println(err)17 }18}19import (20func main() {21 if err != nil {22 fmt.Println(err)23 }24}25import (26func main() {27 if err != nil {28 fmt.Println(err)29 }30}31import (32func main() {33 if err != nil {34 fmt.Println(err)35 }36}

Full Screen

Full Screen

NoBody

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 res := req.Do()4 fmt.Println(res.StatusCode())5 fmt.Println(res.Body())6 fmt.Println(res.String())7 fmt.Println(res.JSON())8 var data map[string]interface{}9 res.JSON(&data)10 fmt.Println(data)11 type Person struct {12 }13 res.JSON(&person)14 fmt.Println(person)15 fmt.Println(res.XML())16 res.XML(&data)17 fmt.Println(data)18 type Dog struct {19 }20 res.XML(&dog)21 fmt.Println(dog)22 fmt.Println(res.YAML())23 res.YAML(&data)24 fmt.Println(data)25 type Cat struct {26 }27 res.YAML(&cat)28 fmt.Println(cat)29 fmt.Println(res.TOML())30 res.TOML(&data)31 fmt.Println(data)32 type Rabbit struct {33 }34 res.TOML(&rabbit)35 fmt.Println(rabbit)36 fmt.Println(res.String())37 fmt.Println(res.Bytes())

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful