Black Lives Matter. Support the Equal Justice Initiative.

Source file src/mime/type_test.go

Documentation: 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  
   152  func BenchmarkTypeByExtension(b *testing.B) {
   153  	initMime()
   154  	b.ResetTimer()
   155  
   156  	for _, ext := range []string{
   157  		".html",
   158  		".HTML",
   159  		".unused",
   160  	} {
   161  		b.Run(ext, func(b *testing.B) {
   162  			b.RunParallel(func(pb *testing.PB) {
   163  				for pb.Next() {
   164  					TypeByExtension(ext)
   165  				}
   166  			})
   167  		})
   168  	}
   169  }
   170  
   171  func BenchmarkExtensionsByType(b *testing.B) {
   172  	initMime()
   173  	b.ResetTimer()
   174  
   175  	for _, typ := range []string{
   176  		"text/html",
   177  		"text/html; charset=utf-8",
   178  		"application/octet-stream",
   179  	} {
   180  		b.Run(typ, func(b *testing.B) {
   181  			b.RunParallel(func(pb *testing.PB) {
   182  				for pb.Next() {
   183  					if _, err := ExtensionsByType(typ); err != nil {
   184  						b.Fatal(err)
   185  					}
   186  				}
   187  			})
   188  		})
   189  	}
   190  }
   191  
   192  func TestExtensionsByType2(t *testing.T) {
   193  	cleanup := setMimeInit(func() {
   194  		clearMimeTypes()
   195  		// Initialize built-in types like in type.go before osInitMime.
   196  		setMimeTypes(builtinTypesLower, builtinTypesLower)
   197  	})
   198  	defer cleanup()
   199  
   200  	tests := []struct {
   201  		typ  string
   202  		want []string
   203  	}{
   204  		{typ: "image/jpeg", want: []string{".jpeg", ".jpg"}},
   205  	}
   206  
   207  	for _, tt := range tests {
   208  		got, err := ExtensionsByType(tt.typ)
   209  		if err != nil {
   210  			t.Errorf("ExtensionsByType(%q): %v", tt.typ, err)
   211  			continue
   212  		}
   213  		if !reflect.DeepEqual(got, tt.want) {
   214  			t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want)
   215  		}
   216  	}
   217  }
   218  

View as plain text