From 4d315f474bd777a7feb489c84ef2e5e5a3355e9c Mon Sep 17 00:00:00 2001 From: Manu Mtz-Almeida Date: Wed, 8 Apr 2015 14:24:49 +0200 Subject: [PATCH] More unit tests --- context.go | 10 +++++ context_test.go | 3 +- gin.go | 24 +---------- input_holder.go | 22 ++++++++++ mode_test.go | 31 ++++++++++++++ response_writer_test.go | 89 +++++++++++++++++++++++++++++++++++++++++ routes_test.go | 53 +++++++++--------------- 7 files changed, 173 insertions(+), 59 deletions(-) create mode 100644 mode_test.go create mode 100644 response_writer_test.go diff --git a/context.go b/context.go index 088fd69..0e45989 100644 --- a/context.go +++ b/context.go @@ -15,6 +15,16 @@ import ( "github.com/gin-gonic/gin/render" ) +const ( + MIMEJSON = binding.MIMEJSON + MIMEHTML = binding.MIMEHTML + MIMEXML = binding.MIMEXML + MIMEXML2 = binding.MIMEXML2 + MIMEPlain = binding.MIMEPlain + MIMEPOSTForm = binding.MIMEPOSTForm + MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm +) + const AbortIndex = math.MaxInt8 / 2 // Context is the most important part of gin. It allows us to pass variables between middleware, diff --git a/context_test.go b/context_test.go index 36e4a59..1d2b42c 100644 --- a/context_test.go +++ b/context_test.go @@ -13,7 +13,6 @@ import ( "testing" "github.com/gin-gonic/gin/binding" - "github.com/julienschmidt/httprouter" "github.com/stretchr/testify/assert" ) @@ -33,7 +32,7 @@ func TestContextReset(t *testing.T) { c.index = 2 c.Writer = &responseWriter{ResponseWriter: httptest.NewRecorder()} - c.Params = httprouter.Params{httprouter.Param{}} + c.Params = Params{Param{}} c.Error(errors.New("test"), nil) c.Set("foo", "bar") c.reset() diff --git a/gin.go b/gin.go index 1965d4b..90f83c0 100644 --- a/gin.go +++ b/gin.go @@ -13,28 +13,6 @@ import ( "github.com/gin-gonic/gin/render" ) -// Param is a single URL parameter, consisting of a key and a value. -type Param struct { - Key string - Value string -} - -// Params is a Param-slice, as returned by the router. -// The slice is ordered, the first URL parameter is also the first slice value. -// It is therefore safe to read values by the index. -type Params []Param - -// ByName returns the value of the first Param which key matches the given name. -// If no matching Param is found, an empty string is returned. -func (ps Params) ByName(name string) string { - for _, entry := range ps { - if entry.Key == name { - return entry.Value - } - } - return "" -} - var default404Body = []byte("404 page not found") var default405Body = []byte("405 method not allowed") @@ -230,7 +208,7 @@ func (engine *Engine) serveHTTPRequest(context *Context) { } } } - context.handlers = engine.allNoMethod + context.handlers = engine.allNoRoute serveError(context, 404, default404Body) } diff --git a/input_holder.go b/input_holder.go index aa5fca9..b40eb28 100644 --- a/input_holder.go +++ b/input_holder.go @@ -4,6 +4,28 @@ package gin +// Param is a single URL parameter, consisting of a key and a value. +type Param struct { + Key string + Value string +} + +// Params is a Param-slice, as returned by the router. +// The slice is ordered, the first URL parameter is also the first slice value. +// It is therefore safe to read values by the index. +type Params []Param + +// ByName returns the value of the first Param which key matches the given name. +// If no matching Param is found, an empty string is returned. +func (ps Params) ByName(name string) string { + for _, entry := range ps { + if entry.Key == name { + return entry.Value + } + } + return "" +} + type inputHolder struct { context *Context } diff --git a/mode_test.go b/mode_test.go new file mode 100644 index 0000000..2a23d85 --- /dev/null +++ b/mode_test.go @@ -0,0 +1,31 @@ +// Copyright 2014 Manu Martinez-Almeida. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func init() { + SetMode(TestMode) +} + +func TestSetMode(t *testing.T) { + SetMode(DebugMode) + assert.Equal(t, ginMode, debugCode) + assert.Equal(t, Mode(), DebugMode) + + SetMode(ReleaseMode) + assert.Equal(t, ginMode, releaseCode) + assert.Equal(t, Mode(), ReleaseMode) + + SetMode(TestMode) + assert.Equal(t, ginMode, testCode) + assert.Equal(t, Mode(), TestMode) + + assert.Panics(t, func() { SetMode("unknown") }) +} diff --git a/response_writer_test.go b/response_writer_test.go new file mode 100644 index 0000000..723acb0 --- /dev/null +++ b/response_writer_test.go @@ -0,0 +1,89 @@ +// Copyright 2014 Manu Martinez-Almeida. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" +) + +var _ ResponseWriter = &responseWriter{} +var _ http.ResponseWriter = &responseWriter{} +var _ http.ResponseWriter = ResponseWriter(&responseWriter{}) + +func init() { + SetMode(TestMode) +} + +func TestResponseWriterReset(t *testing.T) { + testWritter := httptest.NewRecorder() + writer := &responseWriter{} + var w ResponseWriter = writer + + writer.reset(testWritter) + assert.Equal(t, writer.size, -1) + assert.Equal(t, writer.status, 200) + assert.Equal(t, writer.ResponseWriter, testWritter) + assert.Equal(t, w.Size(), -1) + assert.Equal(t, w.Status(), 200) + assert.False(t, w.Written()) +} + +func TestResponseWriterWriteHeader(t *testing.T) { + testWritter := httptest.NewRecorder() + writer := &responseWriter{} + writer.reset(testWritter) + w := ResponseWriter(writer) + + w.WriteHeader(300) + assert.False(t, w.Written()) + assert.Equal(t, w.Status(), 300) + assert.NotEqual(t, testWritter.Code, 300) + + w.WriteHeader(-1) + assert.Equal(t, w.Status(), 300) +} + +func TestResponseWriterWriteHeadersNow(t *testing.T) { + testWritter := httptest.NewRecorder() + writer := &responseWriter{} + writer.reset(testWritter) + w := ResponseWriter(writer) + + w.WriteHeader(300) + w.WriteHeaderNow() + + assert.True(t, w.Written()) + assert.Equal(t, w.Size(), 0) + assert.Equal(t, testWritter.Code, 300) + + writer.size = 10 + w.WriteHeaderNow() + assert.Equal(t, w.Size(), 10) +} + +func TestResponseWriterWrite(t *testing.T) { + testWritter := httptest.NewRecorder() + writer := &responseWriter{} + writer.reset(testWritter) + w := ResponseWriter(writer) + + n, err := w.Write([]byte("hola")) + assert.Equal(t, n, 4) + assert.Equal(t, w.Size(), 4) + assert.Equal(t, w.Status(), 200) + assert.Equal(t, testWritter.Code, 200) + assert.Equal(t, testWritter.Body.String(), "hola") + assert.NoError(t, err) + + n, err = w.Write([]byte(" adios")) + assert.Equal(t, n, 6) + assert.Equal(t, w.Size(), 10) + assert.Equal(t, testWritter.Body.String(), "hola adios") + assert.NoError(t, err) +} diff --git a/routes_test.go b/routes_test.go index ce61a41..fd4d5b6 100644 --- a/routes_test.go +++ b/routes_test.go @@ -11,7 +11,6 @@ import ( "net/http/httptest" "os" "path" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -129,15 +128,9 @@ func TestHandleStaticFile(t *testing.T) { w := performRequest(r, "GET", filePath) // TEST - if w.Code != 200 { - t.Errorf("Response code should be 200, was: %d", w.Code) - } - if w.Body.String() != "Gin Web Framework" { - t.Errorf("Response should be test, was: %s", w.Body.String()) - } - if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" { - t.Errorf("Content-Type should be text/plain, was %s", w.HeaderMap.Get("Content-Type")) - } + assert.Equal(t, w.Code, 200) + assert.Equal(t, w.Body.String(), "Gin Web Framework") + assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8") } // TestHandleStaticDir - ensure the root/sub dir handles properly @@ -151,18 +144,10 @@ func TestHandleStaticDir(t *testing.T) { // TEST bodyAsString := w.Body.String() - if w.Code != 200 { - t.Errorf("Response code should be 200, was: %d", w.Code) - } - if len(bodyAsString) == 0 { - t.Errorf("Got empty body instead of file tree") - } - if !strings.Contains(bodyAsString, "gin.go") { - t.Errorf("Can't find:`gin.go` in file tree: %s", bodyAsString) - } - if w.HeaderMap.Get("Content-Type") != "text/html; charset=utf-8" { - t.Errorf("Content-Type should be text/plain, was %s", w.HeaderMap.Get("Content-Type")) - } + assert.Equal(t, w.Code, 200) + assert.NotEmpty(t, bodyAsString) + assert.Contains(t, bodyAsString, "gin.go") + assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/html; charset=utf-8") } // TestHandleHeadToDir - ensure the root/sub dir handles properly @@ -264,8 +249,8 @@ func TestAbortHandlersChain(t *testing.T) { w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, signature, "ACD") assert.Equal(t, w.Code, 409) + assert.Equal(t, signature, "ACD") } func TestAbortHandlersChainAndNext(t *testing.T) { @@ -286,8 +271,8 @@ func TestAbortHandlersChainAndNext(t *testing.T) { w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, signature, "AB") assert.Equal(t, w.Code, 410) + assert.Equal(t, signature, "AB") } // TestContextParamsGet tests that a parameter can be parsed from the URL. @@ -312,21 +297,21 @@ func TestContextParamsByName(t *testing.T) { // as well as Abort func TestFailHandlersChain(t *testing.T) { // SETUP - var stepsPassed int = 0 - r := New() - r.Use(func(context *Context) { - stepsPassed += 1 + signature := "" + router := New() + router.Use(func(context *Context) { + signature += "A" context.Fail(500, errors.New("foo")) }) - r.Use(func(context *Context) { - stepsPassed += 1 + router.Use(func(context *Context) { + signature += "B" context.Next() - stepsPassed += 1 + signature += "C" }) // RUN - w := performRequest(r, "GET", "/") + w := performRequest(router, "GET", "/") // TEST - assert.Equal(t, w.Code, 500, "Response code should be Server error, was: %d", w.Code) - assert.Equal(t, stepsPassed, 1, "Falied to switch context in handler function: %d", stepsPassed) + assert.Equal(t, w.Code, 500) + assert.Equal(t, signature, "A") }