github.com/naoina/kocha@v0.7.1-0.20171129072645-78c7a531f799/controller_test.go (about)

     1  package kocha_test
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/xml"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"mime"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"os"
    12  	"path/filepath"
    13  	"reflect"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/naoina/kocha"
    18  	"github.com/naoina/kocha/log"
    19  )
    20  
    21  func TestMimeTypeFormats(t *testing.T) {
    22  	var actual interface{} = len(kocha.MimeTypeFormats)
    23  	var expected interface{} = 4
    24  	if !reflect.DeepEqual(actual, expected) {
    25  		t.Errorf(`len(TestMimeTypeFormats) => %#v; want %#v`, actual, expected)
    26  	}
    27  	for k, v := range map[string]string{
    28  
    29  		"application/json": "json",
    30  		"application/xml":  "xml",
    31  		"text/html":        "html",
    32  		"text/plain":       "txt",
    33  	} {
    34  		if _, found := kocha.MimeTypeFormats[k]; !found {
    35  			t.Errorf(`MimeTypeFormats["%#v"] => notfound; want %v`, k, v)
    36  		}
    37  	}
    38  }
    39  
    40  func TestMimeTypeFormats_Get(t *testing.T) {
    41  	actual := kocha.MimeTypeFormats.Get("application/json")
    42  	expected := "json"
    43  	if !reflect.DeepEqual(actual, expected) {
    44  		t.Errorf("Expect %v, but %v", expected, actual)
    45  	}
    46  
    47  	actual = kocha.MimeTypeFormats.Get("text/plain")
    48  	expected = "txt"
    49  	if !reflect.DeepEqual(actual, expected) {
    50  		t.Errorf("Expect %v, but %v", expected, actual)
    51  	}
    52  }
    53  
    54  func TestMimeTypeFormats_Set(t *testing.T) {
    55  	mimeType := "test/mime"
    56  	if kocha.MimeTypeFormats[mimeType] != "" {
    57  		t.Fatalf("Expect none, but %v", kocha.MimeTypeFormats[mimeType])
    58  	}
    59  	expected := "testmimetype"
    60  	kocha.MimeTypeFormats.Set(mimeType, expected)
    61  	defer delete(kocha.MimeTypeFormats, mimeType)
    62  	actual := kocha.MimeTypeFormats[mimeType]
    63  	if !reflect.DeepEqual(actual, expected) {
    64  		t.Errorf("Expect %v, but %v", expected, actual)
    65  	}
    66  }
    67  
    68  func TestMimeTypeFormats_Del(t *testing.T) {
    69  	if kocha.MimeTypeFormats["text/html"] == "" {
    70  		t.Fatal("Expect exists, but not exists")
    71  	}
    72  	kocha.MimeTypeFormats.Del("text/html")
    73  	defer func() {
    74  		kocha.MimeTypeFormats["text/html"] = "html"
    75  	}()
    76  	actual := kocha.MimeTypeFormats["text/html"]
    77  	expected := ""
    78  	if !reflect.DeepEqual(actual, expected) {
    79  		t.Errorf("Expect %v, but %v", expected, actual)
    80  	}
    81  }
    82  
    83  func newTestContext(name, layout string) *kocha.Context {
    84  	app, err := kocha.New(&kocha.Config{
    85  		AppPath:       "testdata",
    86  		AppName:       "appname",
    87  		DefaultLayout: "",
    88  		Template: &kocha.Template{
    89  			PathInfo: kocha.TemplatePathInfo{
    90  				Name: "appname",
    91  				Paths: []string{
    92  					filepath.Join("testdata", "app", "view"),
    93  				},
    94  			},
    95  		},
    96  		RouteTable: []*kocha.Route{
    97  			{
    98  				Name:       name,
    99  				Path:       "/",
   100  				Controller: &kocha.FixtureRootTestCtrl{},
   101  			},
   102  		},
   103  		Logger: &kocha.LoggerConfig{
   104  			Writer: ioutil.Discard,
   105  		},
   106  	})
   107  	if err != nil {
   108  		panic(err)
   109  	}
   110  	req, err := http.NewRequest("GET", "/", nil)
   111  	if err != nil {
   112  		panic(err)
   113  	}
   114  	return &kocha.Context{
   115  		Name:     name,
   116  		Layout:   layout,
   117  		Request:  &kocha.Request{Request: req},
   118  		Response: &kocha.Response{ResponseWriter: httptest.NewRecorder()},
   119  		Params:   &kocha.Params{},
   120  		App:      app,
   121  	}
   122  }
   123  
   124  func TestContext_Render(t *testing.T) {
   125  	func() {
   126  		c := newTestContext("testctrlr_ctx", "")
   127  		data := kocha.OrderedOutputMap{
   128  			"c1": "v1",
   129  			"c2": "v2",
   130  		}
   131  		w := httptest.NewRecorder()
   132  		c.Response = &kocha.Response{ResponseWriter: w}
   133  		if err := c.Render(data); err != nil {
   134  			t.Fatal(err)
   135  		}
   136  		buf, err := ioutil.ReadAll(w.Body)
   137  		if err != nil {
   138  			t.Fatal(err)
   139  		}
   140  		actual := string(buf)
   141  		expect1 := "tmpl_ctx: map[c1:v1 c2:v2]\n"
   142  		expect2 := "tmpl_ctx: map[c2:v2 c1:v1]\n"
   143  		if !reflect.DeepEqual(actual, expect1) && !reflect.DeepEqual(actual, expect2) {
   144  			t.Errorf(`c.Render(%#v) => %#v; want %#v or %#v`, data, actual, expect1, expect2)
   145  		}
   146  		if !reflect.DeepEqual(c.Response.ContentType, "text/html") {
   147  			t.Errorf("Expect %v, but %v", "text/html", c.Response.ContentType)
   148  		}
   149  	}()
   150  
   151  	func() {
   152  		c := newTestContext("testctrlr_ctx", "")
   153  		c.Data = kocha.OrderedOutputMap{
   154  			"c3": "v3",
   155  			"c4": "v4",
   156  		}
   157  		w := httptest.NewRecorder()
   158  		c.Response = &kocha.Response{ResponseWriter: w}
   159  		if err := c.Render(nil); err != nil {
   160  			t.Fatal(err)
   161  		}
   162  		buf, err := ioutil.ReadAll(w.Body)
   163  		if err != nil {
   164  			t.Fatal(err)
   165  		}
   166  		actual := string(buf)
   167  		expected := fmt.Sprintf("tmpl_ctx: %v\n", c.Data)
   168  		if !reflect.DeepEqual(actual, expected) {
   169  			t.Errorf("Expect %q, but %q", expected, actual)
   170  		}
   171  	}()
   172  
   173  	func() {
   174  		c := newTestContext("testctrlr_ctx", "")
   175  		c.Data = kocha.OrderedOutputMap{
   176  			"c5": "v5",
   177  			"c6": "v6",
   178  		}
   179  		ctx := kocha.OrderedOutputMap{
   180  			"c6": "test",
   181  			"c7": "v7",
   182  		}
   183  		w := httptest.NewRecorder()
   184  		c.Response = &kocha.Response{ResponseWriter: w}
   185  		if err := c.Render(ctx); err != nil {
   186  			t.Fatal(err)
   187  		}
   188  		buf, err := ioutil.ReadAll(w.Body)
   189  		if err != nil {
   190  			t.Fatal(err)
   191  		}
   192  		actual := string(buf)
   193  		expected := fmt.Sprintf("tmpl_ctx: %v\n", kocha.OrderedOutputMap{
   194  			"c5": "v5",
   195  			"c6": "test",
   196  			"c7": "v7",
   197  		})
   198  		if !reflect.DeepEqual(actual, expected) {
   199  			t.Errorf("Expect %q, but %q", expected, actual)
   200  		}
   201  	}()
   202  
   203  	func() {
   204  		c := newTestContext("testctrlr_ctx", "")
   205  		ctx := "test_ctx"
   206  		w := httptest.NewRecorder()
   207  		c.Response = &kocha.Response{ResponseWriter: w}
   208  		if err := c.Render(ctx); err != nil {
   209  			t.Fatal(err)
   210  		}
   211  		buf, err := ioutil.ReadAll(w.Body)
   212  		if err != nil {
   213  			t.Fatal(err)
   214  		}
   215  		actual := string(buf)
   216  		expected := "tmpl_ctx: test_ctx\n"
   217  		if !reflect.DeepEqual(actual, expected) {
   218  			t.Errorf("Expect %q, but %q", expected, actual)
   219  		}
   220  	}()
   221  
   222  	func() {
   223  		c := newTestContext("testctrlr_ctx", "")
   224  		c.Data = map[interface{}]interface{}{"c1": "v1"}
   225  		ctx := "test_ctx_override"
   226  		w := httptest.NewRecorder()
   227  		c.Response = &kocha.Response{ResponseWriter: w}
   228  		if err := c.Render(ctx); err != nil {
   229  			t.Fatal(err)
   230  		}
   231  		buf, err := ioutil.ReadAll(w.Body)
   232  		if err != nil {
   233  			t.Fatal(err)
   234  		}
   235  		actual := string(buf)
   236  		expected := "tmpl_ctx: test_ctx_override\n"
   237  		if !reflect.DeepEqual(actual, expected) {
   238  			t.Errorf("Expect %q, but %q", expected, actual)
   239  		}
   240  	}()
   241  
   242  	func() {
   243  		c := newTestContext("testctrlr_ctx", "")
   244  		c.Data = map[interface{}]interface{}{"c1": "v1"}
   245  		if err := c.Render(nil); err != nil {
   246  			t.Fatal(err)
   247  		}
   248  		actual := c.Data
   249  		expected := map[interface{}]interface{}{
   250  			"c1": "v1",
   251  		}
   252  		if !reflect.DeepEqual(actual, expected) {
   253  			t.Errorf("Context.Data => %#v, want %#v", actual, expected)
   254  		}
   255  	}()
   256  
   257  	func() {
   258  		c := newTestContext("testctrlr_ctx", "")
   259  		ctx := map[interface{}]interface{}{"c1": "v1"}
   260  		if err := c.Render(ctx); err != nil {
   261  			t.Fatal(err)
   262  		}
   263  		actual := c.Data
   264  		expected := map[interface{}]interface{}{
   265  			"c1": "v1",
   266  		}
   267  		if !reflect.DeepEqual(actual, expected) {
   268  			t.Errorf("Context.Data => %#v, want %#v", actual, expected)
   269  		}
   270  	}()
   271  }
   272  
   273  func TestContext_Render_withDifferentKeyType(t *testing.T) {
   274  	for _, v := range []struct {
   275  		data   interface{}
   276  		ctx    interface{}
   277  		expect error
   278  	}{
   279  		{map[interface{}]interface{}{"c1": "v1"}, map[string]interface{}{"c2": "v2"}, nil},
   280  		{map[string]interface{}{"c1": "v1"}, map[interface{}]interface{}{"c2": "v2"}, fmt.Errorf("kocha: context: key of type interface {} is not assignable to type string")},
   281  		{map[int]interface{}{1: "v1"}, map[string]interface{}{"2": "v2"}, fmt.Errorf("kocha: context: key of type string is not assignable to type int")},
   282  		{map[string]string{"c1": "v1"}, map[string]interface{}{"c2": "v2"}, fmt.Errorf("kocha: context: value of type interface {} is not assignable to type string")},
   283  		{map[string]int{"c1": 1}, map[string]string{"c2": "v2"}, fmt.Errorf("kocha: context: value of type string is not assignable to type int")},
   284  		{map[string]string{"c1": "v1"}, map[string][]byte{"c2": []byte("v2")}, nil},
   285  		{map[string]interface{}{"c1": "v1"}, map[string]int{"c2": 2}, nil},
   286  	} {
   287  		c := newTestContext("testctrlr_ctx", "")
   288  		c.Data = v.data
   289  		ctx := v.ctx
   290  		actual := fmt.Sprint(c.Render(ctx))
   291  		expect := fmt.Sprint(v.expect)
   292  		if !reflect.DeepEqual(actual, expect) {
   293  			t.Errorf(`c.Render(%#v) => %+v; want %+v`, ctx, actual, expect)
   294  		}
   295  	}
   296  }
   297  
   298  func TestContext_Render_withContentType(t *testing.T) {
   299  	c := newTestContext("testctrlr", "")
   300  	w := httptest.NewRecorder()
   301  	c.Response.ResponseWriter = w
   302  	c.Response.ContentType = "application/json"
   303  	if err := c.Render(nil); err != nil {
   304  		t.Fatal(err)
   305  	}
   306  	buf, err := ioutil.ReadAll(w.Body)
   307  	if err != nil {
   308  		t.Fatal(err)
   309  	}
   310  	actual := string(buf)
   311  	expected := `{"tmpl2":"content"}` + "\n"
   312  	if !reflect.DeepEqual(actual, expected) {
   313  		t.Errorf("Expect %q, but %q", expected, actual)
   314  	}
   315  }
   316  
   317  func TestContext_Render_withMissingTemplateInAppName(t *testing.T) {
   318  	c := newTestContext("testctrlr", "")
   319  	c.App.Config.AppName = "unknownAppName"
   320  	actual := fmt.Sprint(c.Render(nil))
   321  	expect := "kocha: template not found: unknownAppName:testctrlr.html"
   322  	if !reflect.DeepEqual(actual, expect) {
   323  		t.Errorf(`kocha.Render(%#v, %#v) => %+v; want %+v`, c, nil, actual, expect)
   324  	}
   325  }
   326  
   327  func TestContext_Render_withMissingTemplate(t *testing.T) {
   328  	c := newTestContext("testctrlr", "")
   329  	c.Name = "unknownctrlr"
   330  	actual := fmt.Sprint(c.Render(nil))
   331  	expect := "kocha: template not found: appname:unknownctrlr.html"
   332  	if !reflect.DeepEqual(actual, expect) {
   333  		t.Errorf(`kocha.Render(%#v, %#v) => %#v; want %#v`, c, nil, actual, expect)
   334  	}
   335  }
   336  
   337  func TestContext_Render_withAnotherLayout(t *testing.T) {
   338  	c := newTestContext("testctrlr", "another_layout")
   339  	w := httptest.NewRecorder()
   340  	c.Response = &kocha.Response{ResponseWriter: w}
   341  	if err := c.Render(nil); err != nil {
   342  		t.Fatal(err)
   343  	}
   344  	buf, err := ioutil.ReadAll(w.Body)
   345  	if err != nil {
   346  		t.Fatal(err)
   347  	}
   348  	actual := string(buf)
   349  	expected := "Another layout\n"
   350  	if !reflect.DeepEqual(actual, expected) {
   351  		t.Errorf("Expect %q, but %q", expected, actual)
   352  	}
   353  }
   354  
   355  func TestContext_RenderJSON(t *testing.T) {
   356  	c := newTestContext("testctrlr", "")
   357  	w := httptest.NewRecorder()
   358  	c.Response = &kocha.Response{ResponseWriter: w}
   359  	if err := c.RenderJSON(struct{ A, B string }{"hoge", "foo"}); err != nil {
   360  		t.Fatal(err)
   361  	}
   362  	buf, err := ioutil.ReadAll(w.Body)
   363  	if err != nil {
   364  		t.Fatal(err)
   365  	}
   366  	actual := string(buf)
   367  	expected := `{"A":"hoge","B":"foo"}`
   368  	if !reflect.DeepEqual(actual, expected) {
   369  		t.Errorf("Expect %v, but %v", expected, actual)
   370  	}
   371  	if !reflect.DeepEqual(c.Response.ContentType, "application/json") {
   372  		t.Errorf("Expect %v, but %v", "application/json", c.Response.ContentType)
   373  	}
   374  }
   375  
   376  func TestContext_RenderXML(t *testing.T) {
   377  	c := newTestContext("testctrlr", "")
   378  	ctx := struct {
   379  		XMLName xml.Name `xml:"user"`
   380  		A       string   `xml:"id"`
   381  		B       string   `xml:"name"`
   382  	}{A: "hoge", B: "foo"}
   383  	w := httptest.NewRecorder()
   384  	c.Response = &kocha.Response{ResponseWriter: w}
   385  	if err := c.RenderXML(ctx); err != nil {
   386  		t.Fatal(err)
   387  	}
   388  	buf, err := ioutil.ReadAll(w.Body)
   389  	if err != nil {
   390  		t.Fatal(err)
   391  	}
   392  	actual := string(buf)
   393  	expected := "<user><id>hoge</id><name>foo</name></user>"
   394  	if !reflect.DeepEqual(actual, expected) {
   395  		t.Errorf("Expect %v, but %v", expected, actual)
   396  	}
   397  	if !reflect.DeepEqual(c.Response.ContentType, "application/xml") {
   398  		t.Errorf("Expect %v, but %v", "application/xml", c.Response.ContentType)
   399  	}
   400  }
   401  
   402  func TestContext_RenderText(t *testing.T) {
   403  	c := newTestContext("testctrlr", "")
   404  	w := httptest.NewRecorder()
   405  	c.Response = &kocha.Response{ResponseWriter: w}
   406  	if err := c.RenderText("test_content_data"); err != nil {
   407  		t.Fatal(err)
   408  	}
   409  	buf, err := ioutil.ReadAll(w.Body)
   410  	if err != nil {
   411  		t.Fatal(err)
   412  	}
   413  	actual := string(buf)
   414  	expected := "test_content_data"
   415  	if !reflect.DeepEqual(actual, expected) {
   416  		t.Errorf("Expect %v, but %v", expected, actual)
   417  	}
   418  	if !reflect.DeepEqual(c.Response.ContentType, "text/plain") {
   419  		t.Errorf("Expect %v, but %v", "text/plain", c.Response.ContentType)
   420  	}
   421  }
   422  
   423  func TestContext_RenderError(t *testing.T) {
   424  	for _, v := range []struct {
   425  		status      int
   426  		contentType string
   427  		expect      string
   428  	}{
   429  		{http.StatusInternalServerError, "text/html", "500 error\n"},
   430  		{http.StatusBadRequest, "text/html", "400 error\n"},
   431  		{http.StatusInternalServerError, "application/json", "{\"error\":500}\n"},
   432  		{http.StatusTeapot, "text/html", http.StatusText(http.StatusTeapot)},
   433  	} {
   434  		c := newTestContext("testctrlr", "")
   435  		w := httptest.NewRecorder()
   436  		c.Response = &kocha.Response{ResponseWriter: w}
   437  		c.Response.ContentType = v.contentType
   438  		if err := c.RenderError(v.status, nil, nil); err != nil {
   439  			t.Fatal(err)
   440  		}
   441  		buf, err := ioutil.ReadAll(w.Body)
   442  		if err != nil {
   443  			t.Fatal(err)
   444  		}
   445  		var actual interface{} = string(buf)
   446  		var expect interface{} = v.expect
   447  		if !reflect.DeepEqual(actual, expect) {
   448  			t.Errorf(`Context.RenderError(%#v, %#v, %#v) => %#v; want %#v`, v.status, nil, nil, actual, expect)
   449  		}
   450  
   451  		actual = c.Response.StatusCode
   452  		expect = v.status
   453  		if !reflect.DeepEqual(actual, expect) {
   454  			t.Errorf(`Context.RenderError(%#v, %#v, %#v); HTTP status => %#v; want %#v`, v.status, nil, nil, actual, expect)
   455  		}
   456  	}
   457  
   458  	for _, v := range []struct {
   459  		err         error
   460  		contentType string
   461  		expect      error
   462  	}{
   463  		{nil, "unknown/content-type", fmt.Errorf("kocha: unknown Content-Type: unknown/content-type")},
   464  		{fmt.Errorf("expected error"), "unknown/content-type", fmt.Errorf("kocha: unknown Content-Type: unknown/content-type")},
   465  	} {
   466  		c := newTestContext("testctrlr", "")
   467  		var buf bytes.Buffer
   468  		c.App.Logger = log.New(&buf, c.App.Config.Logger.Formatter, c.App.Config.Logger.Level)
   469  		c.Response.ContentType = v.contentType
   470  		var actual interface{} = fmt.Sprint(c.RenderError(http.StatusInternalServerError, v.err, nil))
   471  		var expect interface{} = fmt.Sprint(v.expect)
   472  		if !reflect.DeepEqual(actual, expect) {
   473  			t.Errorf(`Context.RenderError(%#v, %#v, %#v) => %+v; want %+v`, http.StatusInternalServerError, nil, nil, actual, expect)
   474  		}
   475  
   476  		func() {
   477  			actual := buf.String()
   478  			expect := fmt.Sprintf("message:%v", v.err)
   479  			if v.err != nil && !strings.Contains(actual, expect) {
   480  				t.Errorf(`Context.RenderError(%#v, %#v, %#v); log => %#v; want %#v`, http.StatusInternalServerError, v.err, nil, actual, expect)
   481  			}
   482  		}()
   483  	}
   484  }
   485  
   486  func TestContext_SendFile(t *testing.T) {
   487  	// general test
   488  	func() {
   489  		tmpFile, err := ioutil.TempFile("", "TestContextSendFile")
   490  		if err != nil {
   491  			t.Fatal(err)
   492  		}
   493  		defer tmpFile.Close()
   494  		defer os.Remove(tmpFile.Name())
   495  		if _, err := tmpFile.WriteString("foobarbaz"); err != nil {
   496  			t.Fatal(err)
   497  		}
   498  		c := newTestContext("testctrlr", "")
   499  		w := httptest.NewRecorder()
   500  		c.Response = &kocha.Response{ResponseWriter: w}
   501  		if err := c.SendFile(tmpFile.Name()); err != nil {
   502  			t.Fatal(err)
   503  		}
   504  		buf, err := ioutil.ReadAll(w.Body)
   505  		if err != nil {
   506  			t.Fatal(err)
   507  		}
   508  		actual := string(buf)
   509  		expected := "foobarbaz"
   510  		if !reflect.DeepEqual(actual, expected) {
   511  			t.Errorf("Expect %v, but %v", expected, actual)
   512  		}
   513  	}()
   514  
   515  	// test default static path
   516  	func() {
   517  		tmpDir := filepath.Join(os.TempDir(), kocha.StaticDir)
   518  		if err := os.Mkdir(tmpDir, 0755); err != nil {
   519  			t.Fatal(err)
   520  		}
   521  		tmpFile, err := ioutil.TempFile(tmpDir, "TestContextSendFile")
   522  		if err != nil {
   523  			panic(err)
   524  		}
   525  		defer tmpFile.Close()
   526  		defer os.RemoveAll(tmpDir)
   527  		c := newTestContext("testctrlr", "")
   528  		c.App.Config.AppPath = filepath.Dir(tmpDir)
   529  		if _, err := tmpFile.WriteString("foobarbaz"); err != nil {
   530  			t.Fatal(err)
   531  		}
   532  		w := httptest.NewRecorder()
   533  		c.Response = &kocha.Response{ResponseWriter: w}
   534  		if err := c.SendFile(filepath.Base(tmpFile.Name())); err != nil {
   535  			t.Fatal(err)
   536  		}
   537  		buf, err := ioutil.ReadAll(w.Body)
   538  		if err != nil {
   539  			t.Fatal(err)
   540  		}
   541  		actual := string(buf)
   542  		expected := "foobarbaz"
   543  		if !reflect.DeepEqual(actual, expected) {
   544  			t.Errorf("Expect %v, but %v", expected, actual)
   545  		}
   546  	}()
   547  
   548  	// test file not found
   549  	func() {
   550  		c := newTestContext("testctrlr", "")
   551  		w := httptest.NewRecorder()
   552  		c.Response = &kocha.Response{ResponseWriter: w}
   553  		if err := c.SendFile("unknown/path"); err != nil {
   554  			t.Fatal(err)
   555  		}
   556  		buf, err := ioutil.ReadAll(w.Body)
   557  		if err != nil {
   558  			t.Fatal(err)
   559  		}
   560  		actual := string(buf)
   561  		expect := ""
   562  		if !reflect.DeepEqual(actual, expect) {
   563  			t.Errorf(`kocha.SendFile(c, "unknown/path").Proc(res); body => %#v; want %#v`, actual, expect)
   564  		}
   565  	}()
   566  
   567  	// test detect content type by body
   568  	func() {
   569  		tmpFile, err := ioutil.TempFile("", "TestContextSendFile")
   570  		if err != nil {
   571  			t.Fatal(err)
   572  		}
   573  		defer tmpFile.Close()
   574  		defer os.Remove(tmpFile.Name())
   575  		if _, err := tmpFile.WriteString("foobarbaz"); err != nil {
   576  			t.Fatal(err)
   577  		}
   578  		c := newTestContext("testctrlr", "")
   579  		if err := c.SendFile(tmpFile.Name()); err != nil {
   580  			t.Fatal(err)
   581  		}
   582  		actual := c.Response.ContentType
   583  		expected := "text/plain; charset=utf-8"
   584  		if !reflect.DeepEqual(actual, expected) {
   585  			t.Errorf("Expect %v, but %v", expected, actual)
   586  		}
   587  
   588  		c.Response.ContentType = ""
   589  		if _, err := tmpFile.Seek(0, os.SEEK_SET); err != nil {
   590  			t.Fatal(err)
   591  		}
   592  		if _, err := tmpFile.Write([]byte("\x89PNG\x0d\x0a\x1a\x0a")); err != nil {
   593  			t.Fatal(err)
   594  		}
   595  		if err := c.SendFile(tmpFile.Name()); err != nil {
   596  			t.Fatal(err)
   597  		}
   598  		actual = c.Response.ContentType
   599  		expected = "image/png"
   600  		if !reflect.DeepEqual(actual, expected) {
   601  			t.Errorf("Expect %v, but %v", expected, actual)
   602  		}
   603  	}()
   604  
   605  	// test detect content type by ext
   606  	func() {
   607  		currentPath, err := os.Getwd()
   608  		if err != nil {
   609  			t.Fatal(err)
   610  		}
   611  		tmpFile, err := os.Open(filepath.Join(currentPath, "testdata", "public", "test.js"))
   612  		if err != nil {
   613  			t.Fatal(err)
   614  		}
   615  		defer tmpFile.Close()
   616  		mime.AddExtensionType(".js", "application/javascript") // To avoid differences between environments.
   617  		c := newTestContext("testctrlr", "")
   618  		if err := c.SendFile(tmpFile.Name()); err != nil {
   619  			t.Fatal(err)
   620  		}
   621  		actual := c.Response.ContentType
   622  		expected := "application/javascript"
   623  		if !reflect.DeepEqual(actual, expected) {
   624  			t.Errorf("Expect %v, but %v", expected, actual)
   625  		}
   626  	}()
   627  
   628  	// test with included resources
   629  	func() {
   630  		c := newTestContext("testctrlr", "")
   631  		c.App.ResourceSet.Add("testrcname", "foobarbaz")
   632  		w := httptest.NewRecorder()
   633  		c.Response = &kocha.Response{ResponseWriter: w}
   634  		if err := c.SendFile("testrcname"); err != nil {
   635  			t.Fatal(err)
   636  		}
   637  		buf, err := ioutil.ReadAll(w.Body)
   638  		if err != nil {
   639  			t.Fatal(err)
   640  		}
   641  		actual := string(buf)
   642  		expected := "foobarbaz"
   643  		if !reflect.DeepEqual(actual, expected) {
   644  			t.Errorf("Expect %v, but %v", expected, actual)
   645  		}
   646  	}()
   647  
   648  	// test detect content type with included resources
   649  	func() {
   650  		c := newTestContext("testctrlr", "")
   651  		c.Response.ContentType = ""
   652  		c.App.ResourceSet.Add("testrcname", "\x89PNG\x0d\x0a\x1a\x0a")
   653  		if err := c.SendFile("testrcname"); err != nil {
   654  			t.Fatal(err)
   655  		}
   656  		actual := c.Response.ContentType
   657  		expected := "image/png"
   658  		if !reflect.DeepEqual(actual, expected) {
   659  			t.Errorf("Expect %v, but %v", expected, actual)
   660  		}
   661  	}()
   662  }
   663  
   664  func TestContext_Redirect(t *testing.T) {
   665  	c := newTestContext("testctrlr", "")
   666  	for _, v := range []struct {
   667  		redirectURL string
   668  		permanent   bool
   669  		expected    int
   670  	}{
   671  		{"/path/to/redirect/permanently", true, 301},
   672  		{"/path/to/redirect", false, 302},
   673  	} {
   674  		w := httptest.NewRecorder()
   675  		c.Response = &kocha.Response{ResponseWriter: w}
   676  		if err := c.Redirect(v.redirectURL, v.permanent); err != nil {
   677  			t.Fatal(err)
   678  		}
   679  		actual := []interface{}{w.Code, w.HeaderMap.Get("Location")}
   680  		expected := []interface{}{v.expected, v.redirectURL}
   681  		if !reflect.DeepEqual(actual, expected) {
   682  			t.Errorf(`Controller.Redirect("%#v", %#v) => %#v; want %#v`, v.redirectURL, v.permanent, actual, expected)
   683  		}
   684  	}
   685  }