package wrouter import ( "encoding/json" "net/http" "net/http/httptest" "net/url" "strings" "testing" "git.aiterp.net/gisle/wrouter/generate" "git.aiterp.net/gisle/wrouter/response" "git.aiterp.net/gisle/wrouter/auth" ) var pages = []Page{ Page{generate.ID(), "Test Page", "Blurg blurg"}, Page{generate.ID(), "Test Page 2", "Blurg blurg 2"}, Page{generate.ID(), "Stuff", "And things"}, } type Page struct { ID string `json:"id"` Title string `json:"title"` Text string `json:"text"` } type Header struct { ID string `json:"id"` Title string `json:"title"` } type PageForm struct { Title string `json:"title"` Text string `json:"text"` } func listPage(w http.ResponseWriter, req *http.Request, user *auth.User) { headers := make([]Header, len(pages)) for i, page := range pages { headers[i] = Header{page.ID, page.Title} } response.JSON(w, 200, headers) } func createPage(w http.ResponseWriter, req *http.Request, user *auth.User) { title := req.Form.Get("title") text := req.Form.Get("text") if title == "" { response.Text(w, 400, "No title") return } for _, page := range pages { if page.Title == title { response.Text(w, 400, "Title already exists") return } } page := Page{generate.ID(), title, text} pages = append(pages, page) response.JSON(w, 200, page) } func getPage(w http.ResponseWriter, req *http.Request, id string, user *auth.User) { for _, page := range pages { if page.ID == id { response.JSON(w, 200, page) return } } response.Text(w, 404, "Page not found") } func updatePage(w http.ResponseWriter, req *http.Request, id string, user *auth.User) { for _, page := range pages { if page.ID == id { title := req.Form.Get("title") text := req.Form.Get("text") if title != "" { page.Title = title } page.Text = text response.JSON(w, 200, page) return } } response.Text(w, 404, "Page not found") } func deletePage(w http.ResponseWriter, req *http.Request, id string, user *auth.User) { for i, page := range pages { if page.ID == id { pages = append(pages[:i], pages[i+1:]...) response.Empty(w) return } } response.Text(w, 404, "Page not found") } var resource = Resource{listPage, createPage, getPage, updatePage, deletePage} type handlerStruct struct{} func (hs *handlerStruct) ServeHTTP(w http.ResponseWriter, req *http.Request) { req.ParseForm() // Router does this in non-tests if strings.HasPrefix(req.URL.Path, "/page") { resource.Handle("/page", w, req, nil) return } } func runForm(method, url string, data url.Values) (*http.Response, error) { body := strings.NewReader(data.Encode()) req, err := http.NewRequest(method, url, body) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") return http.DefaultClient.Do(req) } func TestResource(t *testing.T) { server := httptest.NewServer(&handlerStruct{}) t.Run("List", func(t *testing.T) { resp, err := http.Get(server.URL + "/page/") if err != nil { t.Error(err) t.Fail() } if resp.StatusCode != 200 { t.Error("Expected status 200, got", resp.StatusCode, resp.Status) t.Fail() } headers := []Header{} err = json.NewDecoder(resp.Body).Decode(&headers) if err != nil { t.Error(err) t.Fail() } if len(headers) < 3 { t.Error("Expected 3 headers, got", len(headers)) t.Fail() } for i, header := range headers { page := pages[i] if header.ID != page.ID { t.Error(header.ID, "!=", page.ID) t.Fail() } if header.Title != page.Title { t.Error(header.Title, "!=", page.Title) t.Fail() } } }) t.Run("Get", func(t *testing.T) { page := pages[1] resp, err := http.Get(server.URL + "/page/" + page.ID) if err != nil { t.Error(err) t.Fail() } if resp.StatusCode != 200 { t.Error("Expected status 200, got", resp.StatusCode, resp.Status) t.Fail() } respPage := Page{} err = json.NewDecoder(resp.Body).Decode(&respPage) if err != nil { t.Error(err) t.Fail() } if respPage.ID == "" { t.Error("No ID in response page") t.Fail() } if respPage.ID != page.ID { t.Errorf("ID %s != %s", respPage.ID, page.ID) t.Fail() } if respPage.Title != page.Title { t.Errorf("Title %s != %s", respPage.Title, page.Title) t.Fail() } if respPage.Text != page.Text { t.Errorf("Text %s != %s", respPage.Text, page.Text) t.Fail() } }) t.Run("Get_Fail", func(t *testing.T) { resp, err := http.Get(server.URL + "/page/" + generate.ID()) if err != nil { t.Error(err) t.Fail() } if resp.StatusCode != 404 { t.Error("Expected status 404, got", resp.StatusCode, resp.Status) t.Fail() } respPage := Page{} err = json.NewDecoder(resp.Body).Decode(&respPage) if err == nil { t.Error("Expected encoder error, got:", respPage) t.Fail() } if respPage.ID != "" { t.Error("Ad ID in response page", respPage.ID) t.Fail() } }) t.Run("Create", func(t *testing.T) { form := url.Values{} form.Set("title", "Hello World") form.Set("text", "Sei Gegrüßt, Erde") resp, err := http.PostForm(server.URL+"/page/", form) if err != nil { t.Error(err) t.Fail() } if resp.StatusCode != 200 { t.Error("Expected status 200, got", resp.StatusCode, resp.Status) t.Fail() } respPage := Page{} err = json.NewDecoder(resp.Body).Decode(&respPage) if err != nil { t.Error(err) t.Fail() } if respPage.ID == "" { t.Error("No ID in response page") t.Fail() } if respPage.Title != form.Get("title") { t.Errorf("Title %s != %s", respPage.Title, form.Get("title")) t.Fail() } if respPage.Text != form.Get("text") { t.Errorf("Text %s != %s", respPage.Text, form.Get("text")) t.Fail() } if len(pages) != 4 { t.Errorf("Page was not added") t.Fail() } }) t.Run("Update", func(t *testing.T) { page := pages[0] form := url.Values{} form.Set("text", "Edits and stuff") resp, err := runForm("PUT", server.URL+"/page/"+page.ID, form) if err != nil { t.Error("Request:", err) t.Fail() } if resp.StatusCode != 200 { t.Error("Expected status 200, got", resp.StatusCode, resp.Status) t.Fail() } respPage := Page{} err = json.NewDecoder(resp.Body).Decode(&respPage) if err != nil { t.Error("Decode:", err) t.Fail() } if respPage.ID == "" { t.Error("No ID in response page") t.Fail() } if respPage.Title != page.Title { t.Errorf("Title %s != %s", respPage.Title, form.Get("title")) t.Fail() } if respPage.Text != form.Get("text") { t.Errorf("Text %s != %s", respPage.Text, form.Get("text")) t.Fail() } }) t.Run("Update_Fail", func(t *testing.T) { form := url.Values{} form.Set("text", "Edits and stuff") resp, err := runForm("PUT", server.URL+"/page/NONEXISTENT-ID-GOES-HERE", form) if err != nil { t.Error("Request:", err) t.Fail() } if resp.StatusCode != 404 { t.Error("Expected status 404, got", resp.StatusCode, resp.Status) t.Fail() } respPage := Page{} err = json.NewDecoder(resp.Body).Decode(&respPage) if err == nil { t.Error("A page was returned:", respPage) t.Fail() } if respPage.ID != "" { t.Error("ID in response page", respPage.ID) t.Fail() } }) t.Run("Delete", func(t *testing.T) { page := pages[3] resp, err := runForm("DELETE", server.URL+"/page/"+page.ID, url.Values{}) if err != nil { t.Error("Request:", err) t.Fail() } if resp.StatusCode != 204 { t.Error("Expected status 204, got", resp.Status) t.Fail() } if len(pages) != 3 { t.Error("Page was not deleted") t.Fail() } }) t.Run("Delete_Fail", func(t *testing.T) { resp, err := runForm("DELETE", server.URL+"/page/NONEXISTENT-ID-GOES-HERE", url.Values{}) if err != nil { t.Error("Request:", err) t.Fail() } if resp.StatusCode != 404 { t.Error("Expected status 404, got", resp.Status) t.Fail() } if len(pages) != 3 { t.Error("A page was deleted despite the non-existent ID") t.Fail() } }) }