github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/mime/type_test.go (about) 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() { 18 testInitMime = nil 19 once = sync.Once{} 20 } 21 } 22 23 func clearMimeTypes() { 24 setMimeTypes(map[string]string{}, map[string]string{}) 25 } 26 27 func setType(ext, typ string) { 28 if !strings.HasPrefix(ext, ".") { 29 panic("missing leading dot") 30 } 31 if err := setExtensionType(ext, typ); err != nil { 32 panic("bad test data: " + err.Error()) 33 } 34 } 35 36 func TestTypeByExtension(t *testing.T) { 37 once = sync.Once{} 38 // initMimeForTests returns the platform-specific extension => 39 // type tests. On Unix and Plan 9, this also tests the parsing 40 // of MIME text files (in testdata/*). On Windows, we test the 41 // real registry on the machine and assume that ".png" exists 42 // there, which empirically it always has, for all versions of 43 // Windows. 44 typeTests := initMimeForTests() 45 46 for ext, want := range typeTests { 47 val := TypeByExtension(ext) 48 if val != want { 49 t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want) 50 } 51 } 52 } 53 54 func TestTypeByExtension_LocalData(t *testing.T) { 55 cleanup := setMimeInit(func() { 56 clearMimeTypes() 57 setType(".foo", "x/foo") 58 setType(".bar", "x/bar") 59 setType(".Bar", "x/bar; capital=1") 60 }) 61 defer cleanup() 62 63 tests := map[string]string{ 64 ".foo": "x/foo", 65 ".bar": "x/bar", 66 ".Bar": "x/bar; capital=1", 67 ".sdlkfjskdlfj": "", 68 ".t1": "", // testdata shouldn't be used 69 } 70 71 for ext, want := range tests { 72 val := TypeByExtension(ext) 73 if val != want { 74 t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want) 75 } 76 } 77 } 78 79 func TestTypeByExtensionCase(t *testing.T) { 80 const custom = "test/test; charset=iso-8859-1" 81 const caps = "test/test; WAS=ALLCAPS" 82 83 cleanup := setMimeInit(func() { 84 clearMimeTypes() 85 setType(".TEST", caps) 86 setType(".tesT", custom) 87 }) 88 defer cleanup() 89 90 // case-sensitive lookup 91 if got := TypeByExtension(".tesT"); got != custom { 92 t.Fatalf("for .tesT, got %q; want %q", got, custom) 93 } 94 if got := TypeByExtension(".TEST"); got != caps { 95 t.Fatalf("for .TEST, got %q; want %s", got, caps) 96 } 97 98 // case-insensitive 99 if got := TypeByExtension(".TesT"); got != custom { 100 t.Fatalf("for .TesT, got %q; want %q", got, custom) 101 } 102 } 103 104 func TestExtensionsByType(t *testing.T) { 105 cleanup := setMimeInit(func() { 106 clearMimeTypes() 107 setType(".gif", "image/gif") 108 setType(".a", "foo/letter") 109 setType(".b", "foo/letter") 110 setType(".B", "foo/letter") 111 setType(".PNG", "image/png") 112 }) 113 defer cleanup() 114 115 tests := []struct { 116 typ string 117 want []string 118 wantErr string 119 }{ 120 {typ: "image/gif", want: []string{".gif"}}, 121 {typ: "image/png", want: []string{".png"}}, // lowercase 122 {typ: "foo/letter", want: []string{".a", ".b"}}, 123 {typ: "x/unknown", want: nil}, 124 } 125 126 for _, tt := range tests { 127 got, err := ExtensionsByType(tt.typ) 128 if err != nil && tt.wantErr != "" && strings.Contains(err.Error(), tt.wantErr) { 129 continue 130 } 131 if err != nil { 132 t.Errorf("ExtensionsByType(%q) error: %v", tt.typ, err) 133 continue 134 } 135 if tt.wantErr != "" { 136 t.Errorf("ExtensionsByType(%q) = %q, %v; want error substring %q", tt.typ, got, err, tt.wantErr) 137 continue 138 } 139 if !reflect.DeepEqual(got, tt.want) { 140 t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want) 141 } 142 } 143 } 144 145 func TestLookupMallocs(t *testing.T) { 146 n := testing.AllocsPerRun(10000, func() { 147 TypeByExtension(".html") 148 TypeByExtension(".HtML") 149 }) 150 if n > 0 { 151 t.Errorf("allocs = %v; want 0", n) 152 } 153 } 154 155 func BenchmarkTypeByExtension(b *testing.B) { 156 initMime() 157 b.ResetTimer() 158 159 for _, ext := range []string{ 160 ".html", 161 ".HTML", 162 ".unused", 163 } { 164 b.Run(ext, func(b *testing.B) { 165 b.RunParallel(func(pb *testing.PB) { 166 for pb.Next() { 167 TypeByExtension(ext) 168 } 169 }) 170 }) 171 } 172 } 173 174 func BenchmarkExtensionsByType(b *testing.B) { 175 initMime() 176 b.ResetTimer() 177 178 for _, typ := range []string{ 179 "text/html", 180 "text/html; charset=utf-8", 181 "application/octet-stream", 182 } { 183 b.Run(typ, func(b *testing.B) { 184 b.RunParallel(func(pb *testing.PB) { 185 for pb.Next() { 186 if _, err := ExtensionsByType(typ); err != nil { 187 b.Fatal(err) 188 } 189 } 190 }) 191 }) 192 } 193 } 194 195 func TestExtensionsByType2(t *testing.T) { 196 cleanup := setMimeInit(func() { 197 clearMimeTypes() 198 // Initialize built-in types like in type.go before osInitMime. 199 setMimeTypes(builtinTypesLower, builtinTypesLower) 200 }) 201 defer cleanup() 202 203 tests := []struct { 204 typ string 205 want []string 206 }{ 207 {typ: "image/jpeg", want: []string{".jpeg", ".jpg"}}, 208 } 209 210 for _, tt := range tests { 211 got, err := ExtensionsByType(tt.typ) 212 if err != nil { 213 t.Errorf("ExtensionsByType(%q): %v", tt.typ, err) 214 continue 215 } 216 if !reflect.DeepEqual(got, tt.want) { 217 t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want) 218 } 219 } 220 }