Home | History | Annotate | Download | only in mime
      1 // Copyright 2010 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package mime
      6 
      7 import (
      8 	"reflect"
      9 	"strings"
     10 	"sync"
     11 	"testing"
     12 )
     13 
     14 func setMimeInit(fn func()) (cleanup func()) {
     15 	once = sync.Once{}
     16 	testInitMime = fn
     17 	return func() { testInitMime = nil }
     18 }
     19 
     20 func clearMimeTypes() {
     21 	setMimeTypes(map[string]string{}, map[string]string{})
     22 }
     23 
     24 func setType(ext, typ string) {
     25 	if !strings.HasPrefix(ext, ".") {
     26 		panic("missing leading dot")
     27 	}
     28 	if err := setExtensionType(ext, typ); err != nil {
     29 		panic("bad test data: " + err.Error())
     30 	}
     31 }
     32 
     33 func TestTypeByExtension(t *testing.T) {
     34 	once = sync.Once{}
     35 	// initMimeForTests returns the platform-specific extension =>
     36 	// type tests. On Unix and Plan 9, this also tests the parsing
     37 	// of MIME text files (in testdata/*). On Windows, we test the
     38 	// real registry on the machine and assume that ".png" exists
     39 	// there, which empirically it always has, for all versions of
     40 	// Windows.
     41 	typeTests := initMimeForTests()
     42 
     43 	for ext, want := range typeTests {
     44 		val := TypeByExtension(ext)
     45 		if val != want {
     46 			t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
     47 		}
     48 	}
     49 }
     50 
     51 func TestTypeByExtension_LocalData(t *testing.T) {
     52 	cleanup := setMimeInit(func() {
     53 		clearMimeTypes()
     54 		setType(".foo", "x/foo")
     55 		setType(".bar", "x/bar")
     56 		setType(".Bar", "x/bar; capital=1")
     57 	})
     58 	defer cleanup()
     59 
     60 	tests := map[string]string{
     61 		".foo":          "x/foo",
     62 		".bar":          "x/bar",
     63 		".Bar":          "x/bar; capital=1",
     64 		".sdlkfjskdlfj": "",
     65 		".t1":           "", // testdata shouldn't be used
     66 	}
     67 
     68 	for ext, want := range tests {
     69 		val := TypeByExtension(ext)
     70 		if val != want {
     71 			t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
     72 		}
     73 	}
     74 }
     75 
     76 func TestTypeByExtensionCase(t *testing.T) {
     77 	const custom = "test/test; charset=iso-8859-1"
     78 	const caps = "test/test; WAS=ALLCAPS"
     79 
     80 	cleanup := setMimeInit(func() {
     81 		clearMimeTypes()
     82 		setType(".TEST", caps)
     83 		setType(".tesT", custom)
     84 	})
     85 	defer cleanup()
     86 
     87 	// case-sensitive lookup
     88 	if got := TypeByExtension(".tesT"); got != custom {
     89 		t.Fatalf("for .tesT, got %q; want %q", got, custom)
     90 	}
     91 	if got := TypeByExtension(".TEST"); got != caps {
     92 		t.Fatalf("for .TEST, got %q; want %s", got, caps)
     93 	}
     94 
     95 	// case-insensitive
     96 	if got := TypeByExtension(".TesT"); got != custom {
     97 		t.Fatalf("for .TesT, got %q; want %q", got, custom)
     98 	}
     99 }
    100 
    101 func TestExtensionsByType(t *testing.T) {
    102 	cleanup := setMimeInit(func() {
    103 		clearMimeTypes()
    104 		setType(".gif", "image/gif")
    105 		setType(".a", "foo/letter")
    106 		setType(".b", "foo/letter")
    107 		setType(".B", "foo/letter")
    108 		setType(".PNG", "image/png")
    109 	})
    110 	defer cleanup()
    111 
    112 	tests := []struct {
    113 		typ     string
    114 		want    []string
    115 		wantErr string
    116 	}{
    117 		{typ: "image/gif", want: []string{".gif"}},
    118 		{typ: "image/png", want: []string{".png"}}, // lowercase
    119 		{typ: "foo/letter", want: []string{".a", ".b"}},
    120 		{typ: "x/unknown", want: nil},
    121 	}
    122 
    123 	for _, tt := range tests {
    124 		got, err := ExtensionsByType(tt.typ)
    125 		if err != nil && tt.wantErr != "" && strings.Contains(err.Error(), tt.wantErr) {
    126 			continue
    127 		}
    128 		if err != nil {
    129 			t.Errorf("ExtensionsByType(%q) error: %v", tt.typ, err)
    130 			continue
    131 		}
    132 		if tt.wantErr != "" {
    133 			t.Errorf("ExtensionsByType(%q) = %q, %v; want error substring %q", tt.typ, got, err, tt.wantErr)
    134 			continue
    135 		}
    136 		if !reflect.DeepEqual(got, tt.want) {
    137 			t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want)
    138 		}
    139 	}
    140 }
    141 
    142 func TestLookupMallocs(t *testing.T) {
    143 	n := testing.AllocsPerRun(10000, func() {
    144 		TypeByExtension(".html")
    145 		TypeByExtension(".HtML")
    146 	})
    147 	if n > 0 {
    148 		t.Errorf("allocs = %v; want 0", n)
    149 	}
    150 }
    151