| // Copyright 2010 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package mime |
| |
| import ( |
| "reflect" |
| "strings" |
| "sync" |
| "testing" |
| ) |
| |
| func setMimeInit(fn func()) (cleanup func()) { |
| once = sync.Once{} |
| testInitMime = fn |
| return func() { testInitMime = nil } |
| } |
| |
| func clearMimeTypes() { |
| setMimeTypes(map[string]string{}, map[string]string{}) |
| } |
| |
| func setType(ext, typ string) { |
| if !strings.HasPrefix(ext, ".") { |
| panic("missing leading dot") |
| } |
| if err := setExtensionType(ext, typ); err != nil { |
| panic("bad test data: " + err.Error()) |
| } |
| } |
| |
| func TestTypeByExtension(t *testing.T) { |
| once = sync.Once{} |
| // initMimeForTests returns the platform-specific extension => |
| // type tests. On Unix and Plan 9, this also tests the parsing |
| // of MIME text files (in testdata/*). On Windows, we test the |
| // real registry on the machine and assume that ".png" exists |
| // there, which empirically it always has, for all versions of |
| // Windows. |
| typeTests := initMimeForTests() |
| |
| for ext, want := range typeTests { |
| val := TypeByExtension(ext) |
| if val != want { |
| t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want) |
| } |
| } |
| } |
| |
| func TestTypeByExtension_LocalData(t *testing.T) { |
| cleanup := setMimeInit(func() { |
| clearMimeTypes() |
| setType(".foo", "x/foo") |
| setType(".bar", "x/bar") |
| setType(".Bar", "x/bar; capital=1") |
| }) |
| defer cleanup() |
| |
| tests := map[string]string{ |
| ".foo": "x/foo", |
| ".bar": "x/bar", |
| ".Bar": "x/bar; capital=1", |
| ".sdlkfjskdlfj": "", |
| ".t1": "", // testdata shouldn't be used |
| } |
| |
| for ext, want := range tests { |
| val := TypeByExtension(ext) |
| if val != want { |
| t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want) |
| } |
| } |
| } |
| |
| func TestTypeByExtensionCase(t *testing.T) { |
| const custom = "test/test; charset=iso-8859-1" |
| const caps = "test/test; WAS=ALLCAPS" |
| |
| cleanup := setMimeInit(func() { |
| clearMimeTypes() |
| setType(".TEST", caps) |
| setType(".tesT", custom) |
| }) |
| defer cleanup() |
| |
| // case-sensitive lookup |
| if got := TypeByExtension(".tesT"); got != custom { |
| t.Fatalf("for .tesT, got %q; want %q", got, custom) |
| } |
| if got := TypeByExtension(".TEST"); got != caps { |
| t.Fatalf("for .TEST, got %q; want %s", got, caps) |
| } |
| |
| // case-insensitive |
| if got := TypeByExtension(".TesT"); got != custom { |
| t.Fatalf("for .TesT, got %q; want %q", got, custom) |
| } |
| } |
| |
| func TestExtensionsByType(t *testing.T) { |
| cleanup := setMimeInit(func() { |
| clearMimeTypes() |
| setType(".gif", "image/gif") |
| setType(".a", "foo/letter") |
| setType(".b", "foo/letter") |
| setType(".B", "foo/letter") |
| setType(".PNG", "image/png") |
| }) |
| defer cleanup() |
| |
| tests := []struct { |
| typ string |
| want []string |
| wantErr string |
| }{ |
| {typ: "image/gif", want: []string{".gif"}}, |
| {typ: "image/png", want: []string{".png"}}, // lowercase |
| {typ: "foo/letter", want: []string{".a", ".b"}}, |
| {typ: "x/unknown", want: nil}, |
| } |
| |
| for _, tt := range tests { |
| got, err := ExtensionsByType(tt.typ) |
| if err != nil && tt.wantErr != "" && strings.Contains(err.Error(), tt.wantErr) { |
| continue |
| } |
| if err != nil { |
| t.Errorf("ExtensionsByType(%q) error: %v", tt.typ, err) |
| continue |
| } |
| if tt.wantErr != "" { |
| t.Errorf("ExtensionsByType(%q) = %q, %v; want error substring %q", tt.typ, got, err, tt.wantErr) |
| continue |
| } |
| if !reflect.DeepEqual(got, tt.want) { |
| t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want) |
| } |
| } |
| } |
| |
| func TestLookupMallocs(t *testing.T) { |
| t.Skip("skipping test on gccgo until it has better escape analysis") |
| n := testing.AllocsPerRun(10000, func() { |
| TypeByExtension(".html") |
| TypeByExtension(".HtML") |
| }) |
| if n > 0 { |
| t.Errorf("allocs = %v; want 0", n) |
| } |
| } |
| |
| func BenchmarkTypeByExtension(b *testing.B) { |
| initMime() |
| b.ResetTimer() |
| |
| for _, ext := range []string{ |
| ".html", |
| ".HTML", |
| ".unused", |
| } { |
| b.Run(ext, func(b *testing.B) { |
| b.RunParallel(func(pb *testing.PB) { |
| for pb.Next() { |
| TypeByExtension(ext) |
| } |
| }) |
| }) |
| } |
| } |
| |
| func BenchmarkExtensionsByType(b *testing.B) { |
| initMime() |
| b.ResetTimer() |
| |
| for _, typ := range []string{ |
| "text/html", |
| "text/html; charset=utf-8", |
| "application/octet-stream", |
| } { |
| b.Run(typ, func(b *testing.B) { |
| b.RunParallel(func(pb *testing.PB) { |
| for pb.Next() { |
| if _, err := ExtensionsByType(typ); err != nil { |
| b.Fatal(err) |
| } |
| } |
| }) |
| }) |
| } |
| } |
| |
| func TestExtensionsByType2(t *testing.T) { |
| cleanup := setMimeInit(func() { |
| clearMimeTypes() |
| // Initialize built-in types like in type.go before osInitMime. |
| setMimeTypes(builtinTypesLower, builtinTypesLower) |
| }) |
| defer cleanup() |
| |
| tests := []struct { |
| typ string |
| want []string |
| }{ |
| {typ: "image/jpeg", want: []string{".jpeg", ".jpg"}}, |
| } |
| |
| for _, tt := range tests { |
| got, err := ExtensionsByType(tt.typ) |
| if err != nil { |
| t.Errorf("ExtensionsByType(%q): %v", tt.typ, err) |
| continue |
| } |
| if !reflect.DeepEqual(got, tt.want) { |
| t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want) |
| } |
| } |
| } |