@@ 1,1 1,337 @@
package c_test
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "html/template"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strings"
+ "testing"
+
+ "git.sr.ht/~evanj/cms/internal/c"
+ mock_c "git.sr.ht/~evanj/cms/internal/c/mock"
+ "github.com/bmizerany/assert"
+ "github.com/golang/mock/gomock"
+ "github.com/google/uuid"
+)
+
+var (
+ tmpl = template.Must(template.New("c_test").Parse("sup earth"))
+)
+
+type server struct{ *c.Controller }
+
+func (s server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ s.HTML(w, r, tmpl, nil)
+}
+
+func TestJSON(t *testing.T) {
+ t.Parallel()
+
+ var (
+ ctrl = gomock.NewController(t)
+ db = mock_c.NewMockdber(ctrl)
+ l *log.Logger
+ s = server{c.New(l, db)}
+ ts = httptest.NewServer(s)
+ )
+
+ res, _ := http.Get(ts.URL)
+ assert.Equal(t, res.StatusCode, http.StatusOK)
+ assert.Equal(t, res.Header.Get("Content-Type"), "application/json")
+}
+
+func TestHTML(t *testing.T) {
+ t.Parallel()
+
+ var (
+ ctrl = gomock.NewController(t)
+ db = mock_c.NewMockdber(ctrl)
+ l *log.Logger
+ s = server{c.New(l, db)}
+ ts = httptest.NewServer(s)
+ )
+
+ req, _ := http.NewRequest("GET", ts.URL, nil)
+ req.Header.Set("Accept", "text/html")
+ res, _ := http.DefaultClient.Do(req)
+ assert.Equal(t, res.StatusCode, http.StatusOK)
+ assert.Equal(t, res.Header.Get("Content-Type"), "text/html")
+}
+
+type server2 struct {
+ *c.Controller
+ it func(string)
+}
+
+func (s server2) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ s.it(s.Method(r))
+ w.WriteHeader(http.StatusOK)
+}
+
+func TestMethodHack(t *testing.T) {
+ t.Parallel()
+
+ var (
+ ctrl = gomock.NewController(t)
+ db = mock_c.NewMockdber(ctrl)
+ l *log.Logger
+ )
+
+ type spec struct {
+ method string
+ withInput bool
+ inputVal string
+ expect string
+ }
+
+ tests := []spec{
+ spec{"GET", false, "", "GET"},
+ spec{"POST", false, "", "POST"},
+ spec{"PUT", false, "", "PUT"},
+ spec{"PATCH", false, "", "PATCH"},
+ spec{"DELETE", false, "", "DELETE"},
+ spec{"POST", true, "GET", "GET"},
+ spec{"POST", true, "POST", "POST"},
+ spec{"POST", true, "PUT", "PUT"},
+ spec{"POST", true, "PATCH", "PATCH"},
+ spec{"POST", true, "DELETE", "DELETE"},
+ }
+
+ for _, test := range tests {
+ var (
+ s = server2{
+ c.New(l, db),
+ func(method string) {
+ assert.Equal(t, method, test.expect)
+ },
+ }
+ ts = httptest.NewServer(s)
+ )
+
+ form := url.Values{}
+ if test.withInput {
+ form.Add("method", test.inputVal)
+ }
+
+ req, _ := http.NewRequest(test.method, ts.URL,
+ strings.NewReader(form.Encode()))
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ res, _ := http.DefaultClient.Do(req)
+ assert.Equal(t, res.StatusCode, http.StatusOK)
+ }
+}
+
+type server3 struct {
+ *c.Controller
+ to string
+}
+
+func (s server3) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ s.Redirect(w, r, s.to)
+}
+
+func TestRedirect(t *testing.T) {
+ t.Parallel()
+
+ var (
+ ctrl = gomock.NewController(t)
+ db = mock_c.NewMockdber(ctrl)
+ l *log.Logger
+ )
+
+ tests := []string{
+ "/space/2",
+ "/contenttype/2/3",
+ "/content/2/3/4/",
+ "/hook/2/3",
+ "/space?space=2",
+ "/contenttype?space=2&contenttype=3",
+ "/content?space=2&contenttype=3&content=4",
+ "/hook/?space=2&hook=3",
+ }
+
+ for _, test := range tests {
+ var (
+ s = server3{c.New(l, db), test}
+ ts = httptest.NewServer(s)
+ val = url.Values{"url": {test}}
+ )
+
+ req, _ := http.NewRequest("GET", ts.URL+test, nil)
+ req.Header.Set("Accept", "text/html")
+ res, _ := http.DefaultClient.Do(req)
+ assert.Equal(t, res.StatusCode, http.StatusTemporaryRedirect)
+ assert.Equal(t, "/redirect?"+val.Encode(), res.Header.Get("Location"))
+ }
+
+ for _, test := range tests {
+ var (
+ s = server3{c.New(l, db), test}
+ ts = httptest.NewServer(s)
+ )
+ buf, _ := json.Marshal(map[string]string{"redirectURL": test})
+ res, _ := http.Get(ts.URL + test)
+ bod, _ := ioutil.ReadAll(res.Body)
+ assert.Equal(t, res.StatusCode, http.StatusOK)
+ assert.Equal(t, string(buf), string(bod))
+ }
+}
+
+type server4 struct {
+ *c.Controller
+}
+
+func (s server4) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ u, err := s.GetCookieUser(w, r)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ s.SetCookieUser(w, r, u)
+ w.WriteHeader(http.StatusOK)
+}
+
+type FakeUser struct{ u, p string }
+
+func (u FakeUser) ID() string { return fmt.Sprintf("id-%s-%s", u.u, u.p) }
+func (u FakeUser) Name() string { return u.u }
+func (u FakeUser) Token() string { return fmt.Sprintf("token-%s-%s", u.u, u.p) }
+
+func TestUserFromBasicAuth(t *testing.T) {
+ t.Parallel()
+
+ var (
+ ctrl = gomock.NewController(t)
+ db = mock_c.NewMockdber(ctrl)
+ l *log.Logger
+ s = server4{c.New(l, db)}
+ ts = httptest.NewServer(s)
+
+ uname = uuid.New().String()
+ upass = uuid.New().String()
+ u = FakeUser{uname, upass}
+ )
+
+ db.EXPECT().UserGet(uname, upass).Return(u, nil).AnyTimes()
+
+ req, _ := http.NewRequest("GET", ts.URL, nil)
+ req.SetBasicAuth(uname, upass)
+
+ res, _ := http.DefaultClient.Do(req)
+ assert.Equal(t, res.StatusCode, http.StatusOK)
+}
+
+func TestUserFromFromCookie(t *testing.T) {
+ t.Parallel()
+
+ var (
+ ctrl = gomock.NewController(t)
+ db = mock_c.NewMockdber(ctrl)
+ l *log.Logger
+ s = server4{c.New(l, db)}
+ ts = httptest.NewServer(s)
+
+ uname = uuid.New().String()
+ upass = uuid.New().String()
+ cookie = uuid.New().String()
+ u = FakeUser{uname, upass}
+ )
+
+ db.EXPECT().UserGetFromToken(cookie).Return(u, nil).AnyTimes()
+
+ req, _ := http.NewRequest("GET", ts.URL, nil)
+ req.AddCookie(&http.Cookie{
+ Name: string(c.KeyUserLogin),
+ Value: cookie,
+ MaxAge: 0,
+ Secure: false,
+ HttpOnly: false,
+ })
+ res, _ := http.DefaultClient.Do(req)
+ assert.Equal(t, res.StatusCode, http.StatusOK)
+}
+
+func TestUserFromFromCookieFail(t *testing.T) {
+ t.Parallel()
+
+ var (
+ ctrl = gomock.NewController(t)
+ db = mock_c.NewMockdber(ctrl)
+ l *log.Logger
+ s = server4{c.New(l, db)}
+ ts = httptest.NewServer(s)
+
+ cookie = uuid.New().String()
+ )
+
+ db.EXPECT().UserGetFromToken(cookie).Return(nil, errors.New("no user")).AnyTimes()
+
+ req, _ := http.NewRequest("GET", ts.URL, nil)
+ res, _ := http.DefaultClient.Do(req)
+ assert.Equal(t, res.StatusCode, http.StatusInternalServerError)
+}
+
+type server5 struct {
+ *c.Controller
+ typ int
+ str string
+}
+
+func (s server5) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ switch s.typ {
+ case 0:
+ s.String(w, r, s.str)
+ break
+ case 1:
+ s.ErrorString(w, r, 500+s.typ, s.str)
+ break
+ case 2:
+ s.Error(w, r, 500+s.typ, s.str)
+ break
+ case 3:
+ s.Error2(w, r, 500+s.typ, errors.New(s.str))
+ break
+ }
+}
+
+func TestStrAndErr(t *testing.T) {
+ t.Parallel()
+
+ var (
+ ctrl = gomock.NewController(t)
+ db = mock_c.NewMockdber(ctrl)
+ l *log.Logger
+ )
+
+ type spec struct {
+ typ int
+ str string
+ }
+
+ tests := []spec{
+ spec{0, "sup earth"},
+ spec{1, "err1"},
+ spec{2, "err2"},
+ spec{3, "err3"},
+ }
+
+ for _, test := range tests {
+ var (
+ s = server5{c.New(l, db), test.typ, test.str}
+ ts = httptest.NewServer(s)
+ )
+ res, _ := http.Get(ts.URL)
+ if test.typ == 0 {
+ assert.Equal(t, res.StatusCode, http.StatusOK)
+ } else {
+ assert.Equal(t, res.StatusCode, 500+test.typ)
+ }
+ }
+
+}