func TestGzip(t *testing.T) {
	req, _ := http.NewRequest(echo.GET, "/", nil)
	rec := httptest.NewRecorder()
	c := echo.NewContext(req, echo.NewResponse(rec), echo.New())
	h := func(c *echo.Context) error {
		return c.String(http.StatusOK, "test")
	}

	// Skip if no Accept-Encoding header
	Gzip()(h)(c)
	assert.Equal(t, http.StatusOK, rec.Code)
	assert.Equal(t, "test", rec.Body.String())

	// Gzip
	req, _ = http.NewRequest(echo.GET, "/", nil)
	req.Header.Set(echo.AcceptEncoding, "gzip")
	rec = httptest.NewRecorder()
	c = echo.NewContext(req, echo.NewResponse(rec), echo.New())
	Gzip()(h)(c)
	assert.Equal(t, http.StatusOK, rec.Code)
	assert.Equal(t, "gzip", rec.Header().Get(echo.ContentEncoding))
	r, err := gzip.NewReader(rec.Body)
	defer r.Close()
	if assert.NoError(t, err) {
		buf := new(bytes.Buffer)
		buf.ReadFrom(r)
		assert.Equal(t, "test", buf.String())
	}
}
func TestStripTrailingSlash(t *testing.T) {
	req, _ := http.NewRequest(echo.GET, "/users/", nil)
	rec := httptest.NewRecorder()
	c := echo.NewContext(req, echo.NewResponse(rec), echo.New())
	StripTrailingSlash()(c)
	assert.Equal(t, "/users", c.Request().URL.Path)
}
func TestRedirectToSlash(t *testing.T) {
	req, _ := http.NewRequest(echo.GET, "/users", nil)
	rec := httptest.NewRecorder()
	c := echo.NewContext(req, echo.NewResponse(rec), echo.New())
	RedirectToSlash(RedirectToSlashOptions{Code: http.StatusTemporaryRedirect})(c)
	assert.Equal(t, http.StatusTemporaryRedirect, rec.Code)
	assert.Equal(t, "/users/", c.Response().Header().Get("Location"))
}
func TestJWTAuth(t *testing.T) {
	req, _ := http.NewRequest(echo.GET, "/", nil)
	rec := httptest.NewRecorder()
	c := echo.NewContext(req, echo.NewResponse(rec), echo.New())
	key := []byte("key")
	fn := func(kid string, method jwt.SigningMethod) ([]byte, error) {
		return key, nil
	}
	ja := JWTAuth(fn)
	token := jwt.New(jwt.SigningMethodHS256)
	token.Claims["foo"] = "bar"
	token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
	ts, err := token.SignedString(key)
	assert.NoError(t, err)

	// Valid credentials
	auth := Bearer + " " + ts
	req.Header.Set(echo.Authorization, auth)
	assert.NoError(t, ja(c))

	//---------------------
	// Invalid credentials
	//---------------------

	// Expired token
	token.Claims["exp"] = time.Now().Add(-time.Second).Unix()
	ts, err = token.SignedString(key)
	assert.NoError(t, err)
	auth = Bearer + " " + ts
	req.Header.Set(echo.Authorization, auth)
	he := ja(c).(*echo.HTTPError)
	assert.Equal(t, http.StatusUnauthorized, he.Code())

	// Empty Authorization header
	req.Header.Set(echo.Authorization, "")
	he = ja(c).(*echo.HTTPError)
	assert.Equal(t, http.StatusBadRequest, he.Code())

	// Invalid Authorization header
	auth = "token"
	req.Header.Set(echo.Authorization, auth)
	he = ja(c).(*echo.HTTPError)
	assert.Equal(t, http.StatusBadRequest, he.Code())

	// Invalid scheme
	auth = "Bear token"
	req.Header.Set(echo.Authorization, auth)
	he = ja(c).(*echo.HTTPError)
	assert.Equal(t, http.StatusBadRequest, he.Code())

	// WebSocket
	c.Request().Header.Set(echo.Upgrade, echo.WebSocket)
	assert.NoError(t, ja(c))
}
func TestCORS(t *testing.T) {
	mw := cors()
	req := testRequest(nil, "GET", "/", nil)
	res := httptest.NewRecorder()
	c := echo.NewContext(req.Request, echo.NewResponse(res), echo.New())
	called := false

	next := func(c *echo.Context) error {
		called = true
		return nil
	}

	// It calls the next middleware when no origin is set
	h := mw(next)
	h(c)
	assert.True(t, called)
	assert.Empty(t, res.Header().Get("Access-Control-Allow-Origin"))

	// It sets CORS headers and calls the next middleware when the origin is set
	req.Header.Set("Origin", "china")
	called = false
	h(c)
	assert.True(t, called)
	assert.NotEmpty(t, res.Header().Get("Access-Control-Allow-Origin"))

	// It sets CORS headers, ends the middleware chain and
	// returns 200 when receiving a preflight request
	req.Method = "OPTIONS"
	res = httptest.NewRecorder()
	c = echo.NewContext(req.Request, echo.NewResponse(res), echo.New())
	res.Code = 0
	called = false
	h(c)
	assert.False(t, called)
	assert.Equal(t, 200, res.Code)
	assert.NotEmpty(t, res.Header().Get("Access-Control-Allow-Origin"))
	assert.NotEmpty(t, res.Header().Get("Access-Control-Allow-Methods"))
	assert.NotEmpty(t, res.Header().Get("Access-Control-Allow-Headers"))
}
func TestRecover(t *testing.T) {
	e := echo.New()
	e.SetDebug(true)
	req, _ := http.NewRequest(echo.GET, "/", nil)
	rec := httptest.NewRecorder()
	c := echo.NewContext(req, echo.NewResponse(rec), e)
	h := func(c *echo.Context) error {
		panic("test")
	}
	Recover()(h)(c)
	assert.Equal(t, http.StatusInternalServerError, rec.Code)
	assert.Contains(t, rec.Body.String(), "panic recover")
}
func TestLogger(t *testing.T) {
	e := echo.New()
	req, _ := http.NewRequest(echo.GET, "/", nil)
	rec := httptest.NewRecorder()
	c := echo.NewContext(req, echo.NewResponse(rec), e)

	// Status 2xx
	h := func(c *echo.Context) error {
		return c.String(http.StatusOK, "test")
	}
	Logger()(h)(c)

	// Status 3xx
	rec = httptest.NewRecorder()
	c = echo.NewContext(req, echo.NewResponse(rec), e)
	h = func(c *echo.Context) error {
		return c.String(http.StatusTemporaryRedirect, "test")
	}
	Logger()(h)(c)

	// Status 4xx
	rec = httptest.NewRecorder()
	c = echo.NewContext(req, echo.NewResponse(rec), e)
	h = func(c *echo.Context) error {
		return c.String(http.StatusNotFound, "test")
	}
	Logger()(h)(c)

	// Status 5xx with empty path
	req, _ = http.NewRequest(echo.GET, "", nil)
	rec = httptest.NewRecorder()
	c = echo.NewContext(req, echo.NewResponse(rec), e)
	h = func(c *echo.Context) error {
		return errors.New("error")
	}
	Logger()(h)(c)
}
func TestBasicAuth(t *testing.T) {
	req, _ := http.NewRequest(echo.GET, "/", nil)
	rec := httptest.NewRecorder()
	c := echo.NewContext(req, echo.NewResponse(rec), echo.New())
	fn := func(u, p string) bool {
		if u == "joe" && p == "secret" {
			return true
		}
		return false
	}
	ba := BasicAuth(fn)

	// Valid credentials
	auth := Basic + " " + base64.StdEncoding.EncodeToString([]byte("joe:secret"))
	req.Header.Set(echo.Authorization, auth)
	assert.NoError(t, ba(c))

	//---------------------
	// Invalid credentials
	//---------------------

	// Incorrect password
	auth = Basic + " " + base64.StdEncoding.EncodeToString([]byte("joe:password"))
	req.Header.Set(echo.Authorization, auth)
	he := ba(c).(*echo.HTTPError)
	assert.Equal(t, http.StatusUnauthorized, he.Code())

	// Empty Authorization header
	req.Header.Set(echo.Authorization, "")
	he = ba(c).(*echo.HTTPError)
	assert.Equal(t, http.StatusBadRequest, he.Code())

	// Invalid Authorization header
	auth = base64.StdEncoding.EncodeToString([]byte(" :secret"))
	req.Header.Set(echo.Authorization, auth)
	he = ba(c).(*echo.HTTPError)
	assert.Equal(t, http.StatusBadRequest, he.Code())

	// Invalid scheme
	auth = "Base " + base64.StdEncoding.EncodeToString([]byte(" :secret"))
	req.Header.Set(echo.Authorization, auth)
	he = ba(c).(*echo.HTTPError)
	assert.Equal(t, http.StatusBadRequest, he.Code())

	// WebSocket
	c.Request().Header.Set(echo.Upgrade, echo.WebSocket)
	assert.NoError(t, ba(c))
}