func Test_Render_NoRace(t *testing.T) { // This test used to fail if run with -race m := martini.Classic() m.Use(Renderer(Options{ Directory: "fixtures/basic", })) // routing m.Get("/foobar", func(r Render) { r.HTML(200, "hello", "world") }) done := make(chan bool) doreq := func() { res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 200) expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8") // ContentLength should be deferred to the ResponseWriter and not Render expect(t, res.Header().Get(ContentLength), "") expect(t, res.Body.String(), "<h1>Hello world</h1>\n") done <- true } // Run two requests to check there is no race condition go doreq() go doreq() <-done <-done }
func performFileTest(t *testing.T, binder handlerFunc, testCase fileTestCase) { httpRecorder := httptest.NewRecorder() m := martini.Classic() fileTestHandler := func(actual BlogPost, errs Errors) { assertFileAsExpected(t, testCase, actual.HeaderImage, testCase.singleFile) if len(testCase.multipleFiles) != len(actual.Pictures) { t.Errorf("For '%s': Expected %d multiple files, but actually had %d instead", testCase.description, len(testCase.multipleFiles), len(actual.Pictures)) } for i, expectedFile := range testCase.multipleFiles { if i >= len(actual.Pictures) { break } assertFileAsExpected(t, testCase, actual.Pictures[i], expectedFile) } } m.Post(testRoute, binder(BlogPost{}), func(actual BlogPost, errs Errors) { fileTestHandler(actual, errs) }) m.ServeHTTP(httpRecorder, buildRequestWithFile(testCase)) switch httpRecorder.Code { case http.StatusNotFound: panic("Routing is messed up in test fixture (got 404): check methods and paths") case http.StatusInternalServerError: panic("Something bad happened on '" + testCase.description + "'") } }
func Test_Render_Funcs(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ Directory: "fixtures/custom_funcs", Funcs: []template.FuncMap{ { "myCustomFunc": func() string { return "My custom function" }, }, }, })) // routing m.Get("/foobar", func(r Render) { r.HTML(200, "index", "jeremy") }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Body.String(), "My custom function\n") }
func performMultipartFormTest(t *testing.T, binder handlerFunc, testCase multipartFormTestCase) { httpRecorder := httptest.NewRecorder() m := martini.Classic() m.Post(testRoute, binder(BlogPost{}), func(actual BlogPost, errs Errors) { if testCase.shouldSucceed && len(errs) > 0 { t.Errorf("'%s' should have succeeded, but there were errors (%d):\n%+v", testCase.description, len(errs), errs) } else if !testCase.shouldSucceed && len(errs) == 0 { t.Errorf("'%s' should not have succeeded, but it did (there were no errors)", testCase.description) } expString := fmt.Sprintf("%+v", testCase.inputAndExpected) actString := fmt.Sprintf("%+v", actual) if actString != expString { t.Errorf("'%s': expected\n'%s'\nbut got\n'%s'", testCase.description, expString, actString) } }) multipartPayload, mpWriter := makeMultipartPayload(testCase) req, err := http.NewRequest("POST", testRoute, multipartPayload) if err != nil { panic(err) } req.Header.Add("Content-Type", mpWriter.FormDataContentType()) err = mpWriter.Close() if err != nil { panic(err) } if testCase.callFormValueBefore { req.FormValue("foo") } m.ServeHTTP(httpRecorder, req) switch httpRecorder.Code { case http.StatusNotFound: panic("Routing is messed up in test fixture (got 404): check methods and paths") case http.StatusInternalServerError: panic("Something bad happened on '" + testCase.description + "'") } }
// When binding from Form data, testing the type of data to bind // and converting a string into that type is tedious, so these tests // cover all those cases. func TestSetWithProperType(t *testing.T) { testInputs := map[string]string{ "successful": `integer=-1&integer8=-8&integer16=-16&integer32=-32&integer64=-64&uinteger=1&uinteger8=8&uinteger16=16&uinteger32=32&uinteger64=64&boolean_1=true&fl32_1=32.3232&fl64_1=-64.6464646464&str=string`, "errorful": `integer=&integer8=asdf&integer16=--&integer32=&integer64=dsf&uinteger=&uinteger8=asdf&uinteger16=+&uinteger32= 32 &uinteger64=+%20+&boolean_1=&boolean_2=asdf&fl32_1=asdf&fl32_2=&fl64_1=&fl64_2=asdfstr`, } expectedOutputs := map[string]Everything{ "successful": Everything{ Integer: -1, Integer8: -8, Integer16: -16, Integer32: -32, Integer64: -64, Uinteger: 1, Uinteger8: 8, Uinteger16: 16, Uinteger32: 32, Uinteger64: 64, Boolean_1: true, Fl32_1: 32.3232, Fl64_1: -64.6464646464, Str: "string", }, "errorful": Everything{}, } for key, testCase := range testInputs { httpRecorder := httptest.NewRecorder() m := martini.Classic() m.Post(testRoute, Form(Everything{}), func(actual Everything, errs Errors) { actualStr := fmt.Sprintf("%+v", actual) expectedStr := fmt.Sprintf("%+v", expectedOutputs[key]) if actualStr != expectedStr { t.Errorf("For '%s' expected\n%s but got\n%s", key, expectedStr, actualStr) } }) req, err := http.NewRequest("POST", testRoute, strings.NewReader(testCase)) if err != nil { panic(err) } req.Header.Set("Content-Type", formContentType) m.ServeHTTP(httpRecorder, req) } }
func Test_Render_Bad_HTML(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ Directory: "fixtures/basic", })) // routing m.Get("/foobar", func(r Render) { r.HTML(200, "nope", nil) }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 500) expect(t, res.Body.String(), "html/template: \"nope\" is undefined\n") }
func Test_Render_Layout_Current(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ Directory: "fixtures/basic", Layout: "current_layout", })) // routing m.Get("/foobar", func(r Render) { r.HTML(200, "content", "jeremy") }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Body.String(), "content head\n<h1>jeremy</h1>\n\ncontent foot\n") }
func main() { // Initialize m := martini.Classic() // Connect to mongo m.Use(middlewares.Connect()) // Templating support m.Use(middlewares.Templates()) // Routes m.Get("/", articles.List) m.Get("/new", articles.AddEdit) m.Post("/articles", binding.Form(models.Article{}), articles.Add) m.Get("/articles/:_id", articles.Show) // Start listening m.Run() }
func Test_Render_XML(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ // nothing here to configure })) // routing m.Get("/foobar", func(r Render) { r.XML(300, GreetingXML{One: "hello", Two: "world"}) }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 300) expect(t, res.Header().Get(ContentType), ContentXML+"; charset=UTF-8") expect(t, res.Body.String(), `<greeting one="hello" two="world"></greeting>`) }
func Test_Render_Charset_JSON(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ Charset: "foobar", })) // routing m.Get("/foobar", func(r Render) { r.JSON(300, Greeting{"hello", "world"}) }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 300) expect(t, res.Header().Get(ContentType), ContentJSON+"; charset=foobar") expect(t, res.Body.String(), `{"one":"hello","two":"world"}`) }
func Test_Render_BinaryData(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ // nothing here to configure })) // routing m.Get("/foobar", func(r Render) { r.Data(200, []byte("hello there")) }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 200) expect(t, res.Header().Get(ContentType), ContentBinary) expect(t, res.Body.String(), "hello there") }
func Test_Render_Nested_HTML(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ Directory: "fixtures/basic", })) // routing m.Get("/foobar", func(r Render) { r.HTML(200, "admin/index", "jeremy") }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 200) expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8") expect(t, res.Body.String(), "<h1>Admin jeremy</h1>\n") }
func Test_Render_JSON_Prefix(t *testing.T) { m := martini.Classic() prefix := ")]}',\n" m.Use(Renderer(Options{ PrefixJSON: []byte(prefix), })) // routing m.Get("/foobar", func(r Render) { r.JSON(300, Greeting{"hello", "world"}) }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 300) expect(t, res.Header().Get(ContentType), ContentJSON+"; charset=UTF-8") expect(t, res.Body.String(), prefix+`{"one":"hello","two":"world"}`) }
func Test_Render_Delimiters(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ Delims: Delims{"{[{", "}]}"}, Directory: "fixtures/basic", })) // routing m.Get("/foobar", func(r Render) { r.HTML(200, "delims", "jeremy") }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 200) expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8") expect(t, res.Body.String(), "<h1>Hello jeremy</h1>") }
func Test_Render_Extensions(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ Directory: "fixtures/basic", Extensions: []string{".tmpl", ".html"}, })) // routing m.Get("/foobar", func(r Render) { r.HTML(200, "hypertext", nil) }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 200) expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8") expect(t, res.Body.String(), "Hypertext!\n") }
func Test_Render_Default_Charset_HTML(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ Directory: "fixtures/basic", })) // routing m.Get("/foobar", func(r Render) { r.HTML(200, "hello", "jeremy") }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 200) expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8") // ContentLength should be deferred to the ResponseWriter and not Render expect(t, res.Header().Get(ContentLength), "") expect(t, res.Body.String(), "<h1>Hello jeremy</h1>\n") }
func Test_Render_Override_Layout(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ Directory: "fixtures/basic", Layout: "layout", })) // routing m.Get("/foobar", func(r Render) { r.HTML(200, "content", "jeremy", HTMLOptions{ Layout: "another_layout", }) }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/foobar", nil) m.ServeHTTP(res, req) expect(t, res.Code, 200) expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8") expect(t, res.Body.String(), "another head\n<h1>jeremy</h1>\n\nanother foot\n") }
func performFormTest(t *testing.T, binder handlerFunc, testCase formTestCase) { httpRecorder := httptest.NewRecorder() m := martini.Classic() formTestHandler := func(actual interface{}, errs Errors) { if testCase.shouldSucceed && len(errs) > 0 { t.Errorf("'%s' should have succeeded, but there were errors (%d):\n%+v", testCase.description, len(errs), errs) } else if !testCase.shouldSucceed && len(errs) == 0 { t.Errorf("'%s' should have had errors, but there were none", testCase.description) } expString := fmt.Sprintf("%+v", testCase.expected) actString := fmt.Sprintf("%+v", actual) if actString != expString && !(testCase.deepEqual && reflect.DeepEqual(testCase.expected, actual)) { t.Errorf("'%s': expected\n'%s'\nbut got\n'%s'", testCase.description, expString, actString) } } switch testCase.expected.(type) { case Post: if testCase.withInterface { m.Post(testRoute, binder(Post{}, (*modeler)(nil)), func(actual Post, iface modeler, errs Errors) { if actual.Title != iface.Model() { t.Errorf("For '%s': expected the struct to be mapped to the context as an interface", testCase.description) } formTestHandler(actual, errs) }) } else { m.Post(testRoute, binder(Post{}), func(actual Post, errs Errors) { formTestHandler(actual, errs) }) m.Get(testRoute, binder(Post{}), func(actual Post, errs Errors) { formTestHandler(actual, errs) }) } case BlogPost: if testCase.withInterface { m.Post(testRoute, binder(BlogPost{}, (*modeler)(nil)), func(actual BlogPost, iface modeler, errs Errors) { if actual.Title != iface.Model() { t.Errorf("For '%s': expected the struct to be mapped to the context as an interface", testCase.description) } formTestHandler(actual, errs) }) } else { m.Post(testRoute, binder(BlogPost{}), func(actual BlogPost, errs Errors) { formTestHandler(actual, errs) }) } case EmbedPerson: m.Post(testRoute, binder(EmbedPerson{}), func(actual EmbedPerson, errs Errors) { formTestHandler(actual, errs) }) m.Get(testRoute, binder(EmbedPerson{}), func(actual EmbedPerson, errs Errors) { formTestHandler(actual, errs) }) } if testCase.method == "" { testCase.method = "POST" } req, err := http.NewRequest(testCase.method, testRoute+testCase.queryString, strings.NewReader(testCase.payload)) if err != nil { panic(err) } req.Header.Set("Content-Type", testCase.contentType) m.ServeHTTP(httpRecorder, req) switch httpRecorder.Code { case http.StatusNotFound: panic("Routing is messed up in test fixture (got 404): check methods and paths") case http.StatusInternalServerError: panic("Something bad happened on '" + testCase.description + "'") } }
func performJsonTest(t *testing.T, binder handlerFunc, testCase jsonTestCase) { var payload io.Reader httpRecorder := httptest.NewRecorder() m := martini.Classic() jsonTestHandler := func(actual interface{}, errs Errors) { if testCase.shouldSucceedOnJson && len(errs) > 0 { t.Errorf("'%s' should have succeeded, but there were errors (%d):\n%+v", testCase.description, len(errs), errs) } else if !testCase.shouldSucceedOnJson && len(errs) == 0 { t.Errorf("'%s' should NOT have succeeded, but there were NO errors", testCase.description) } expString := fmt.Sprintf("%+v", testCase.expected) actString := fmt.Sprintf("%+v", actual) if actString != expString { t.Errorf("'%s': expected\n'%s'\nbut got\n'%s'", testCase.description, expString, actString) } } switch testCase.expected.(type) { case []Post: if testCase.withInterface { m.Post(testRoute, binder([]Post{}, (*modeler)(nil)), func(actual []Post, iface modeler, errs Errors) { for _, a := range actual { if a.Title != iface.Model() { t.Errorf("For '%s': expected the struct to be mapped to the context as an interface", testCase.description) } jsonTestHandler(a, errs) } }) } else { m.Post(testRoute, binder([]Post{}), func(actual []Post, errs Errors) { jsonTestHandler(actual, errs) }) } case Post: if testCase.withInterface { m.Post(testRoute, binder(Post{}, (*modeler)(nil)), func(actual Post, iface modeler, errs Errors) { if actual.Title != iface.Model() { t.Errorf("For '%s': expected the struct to be mapped to the context as an interface", testCase.description) } jsonTestHandler(actual, errs) }) } else { m.Post(testRoute, binder(Post{}), func(actual Post, errs Errors) { jsonTestHandler(actual, errs) }) } case BlogPost: if testCase.withInterface { m.Post(testRoute, binder(BlogPost{}, (*modeler)(nil)), func(actual BlogPost, iface modeler, errs Errors) { if actual.Title != iface.Model() { t.Errorf("For '%s': expected the struct to be mapped to the context as an interface", testCase.description) } jsonTestHandler(actual, errs) }) } else { m.Post(testRoute, binder(BlogPost{}), func(actual BlogPost, errs Errors) { jsonTestHandler(actual, errs) }) } } if testCase.payload == "-nil-" { payload = nil } else { payload = strings.NewReader(testCase.payload) } req, err := http.NewRequest("POST", testRoute, payload) if err != nil { panic(err) } req.Header.Set("Content-Type", testCase.contentType) m.ServeHTTP(httpRecorder, req) switch httpRecorder.Code { case http.StatusNotFound: panic("Routing is messed up in test fixture (got 404): check method and path") case http.StatusInternalServerError: panic("Something bad happened on '" + testCase.description + "'") default: if testCase.shouldSucceedOnJson && httpRecorder.Code != http.StatusOK && !testCase.shouldFailOnBind { t.Errorf("'%s' should have succeeded (except when using Bind, where it should fail), but returned HTTP status %d with body '%s'", testCase.description, httpRecorder.Code, httpRecorder.Body.String()) } } }