github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/media/mediaType_test.go (about)

     1  // Copyright 2019 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package media
    15  
    16  import (
    17  	"encoding/json"
    18  	"io/ioutil"
    19  	"path/filepath"
    20  	"sort"
    21  	"strings"
    22  	"testing"
    23  
    24  	qt "github.com/frankban/quicktest"
    25  	"github.com/gohugoio/hugo/common/paths"
    26  )
    27  
    28  func TestDefaultTypes(t *testing.T) {
    29  	c := qt.New(t)
    30  	for _, test := range []struct {
    31  		tp               Type
    32  		expectedMainType string
    33  		expectedSubType  string
    34  		expectedSuffix   string
    35  		expectedType     string
    36  		expectedString   string
    37  	}{
    38  		{CalendarType, "text", "calendar", "ics", "text/calendar", "text/calendar"},
    39  		{CSSType, "text", "css", "css", "text/css", "text/css"},
    40  		{SCSSType, "text", "x-scss", "scss", "text/x-scss", "text/x-scss"},
    41  		{CSVType, "text", "csv", "csv", "text/csv", "text/csv"},
    42  		{HTMLType, "text", "html", "html", "text/html", "text/html"},
    43  		{JavascriptType, "application", "javascript", "js", "application/javascript", "application/javascript"},
    44  		{TypeScriptType, "application", "typescript", "ts", "application/typescript", "application/typescript"},
    45  		{TSXType, "text", "tsx", "tsx", "text/tsx", "text/tsx"},
    46  		{JSXType, "text", "jsx", "jsx", "text/jsx", "text/jsx"},
    47  		{JSONType, "application", "json", "json", "application/json", "application/json"},
    48  		{RSSType, "application", "rss", "xml", "application/rss+xml", "application/rss+xml"},
    49  		{SVGType, "image", "svg", "svg", "image/svg+xml", "image/svg+xml"},
    50  		{TextType, "text", "plain", "txt", "text/plain", "text/plain"},
    51  		{XMLType, "application", "xml", "xml", "application/xml", "application/xml"},
    52  		{TOMLType, "application", "toml", "toml", "application/toml", "application/toml"},
    53  		{YAMLType, "application", "yaml", "yaml", "application/yaml", "application/yaml"},
    54  		{PDFType, "application", "pdf", "pdf", "application/pdf", "application/pdf"},
    55  		{TrueTypeFontType, "font", "ttf", "ttf", "font/ttf", "font/ttf"},
    56  		{OpenTypeFontType, "font", "otf", "otf", "font/otf", "font/otf"},
    57  	} {
    58  		c.Assert(test.tp.MainType, qt.Equals, test.expectedMainType)
    59  		c.Assert(test.tp.SubType, qt.Equals, test.expectedSubType)
    60  
    61  		c.Assert(test.tp.Type(), qt.Equals, test.expectedType)
    62  		c.Assert(test.tp.String(), qt.Equals, test.expectedString)
    63  
    64  	}
    65  
    66  	c.Assert(len(DefaultTypes), qt.Equals, 33)
    67  }
    68  
    69  func TestGetByType(t *testing.T) {
    70  	c := qt.New(t)
    71  
    72  	types := Types{HTMLType, RSSType}
    73  
    74  	mt, found := types.GetByType("text/HTML")
    75  	c.Assert(found, qt.Equals, true)
    76  	c.Assert(HTMLType, qt.Equals, mt)
    77  
    78  	_, found = types.GetByType("text/nono")
    79  	c.Assert(found, qt.Equals, false)
    80  
    81  	mt, found = types.GetByType("application/rss+xml")
    82  	c.Assert(found, qt.Equals, true)
    83  	c.Assert(RSSType, qt.Equals, mt)
    84  
    85  	mt, found = types.GetByType("application/rss")
    86  	c.Assert(found, qt.Equals, true)
    87  	c.Assert(RSSType, qt.Equals, mt)
    88  }
    89  
    90  func TestGetByMainSubType(t *testing.T) {
    91  	c := qt.New(t)
    92  	f, found := DefaultTypes.GetByMainSubType("text", "plain")
    93  	c.Assert(found, qt.Equals, true)
    94  	c.Assert(f, qt.Equals, TextType)
    95  	_, found = DefaultTypes.GetByMainSubType("foo", "plain")
    96  	c.Assert(found, qt.Equals, false)
    97  }
    98  
    99  func TestBySuffix(t *testing.T) {
   100  	c := qt.New(t)
   101  	formats := DefaultTypes.BySuffix("xml")
   102  	c.Assert(len(formats), qt.Equals, 2)
   103  	c.Assert(formats[0].SubType, qt.Equals, "rss")
   104  	c.Assert(formats[1].SubType, qt.Equals, "xml")
   105  }
   106  
   107  func TestGetFirstBySuffix(t *testing.T) {
   108  	c := qt.New(t)
   109  
   110  	types := DefaultTypes
   111  
   112  	// Issue #8406
   113  	geoJSON := newMediaTypeWithMimeSuffix("application", "geo", "json", []string{"geojson", "gjson"})
   114  	types = append(types, geoJSON)
   115  	sort.Sort(types)
   116  
   117  	check := func(suffix string, expectedType Type) {
   118  		t, f, found := types.GetFirstBySuffix(suffix)
   119  		c.Assert(found, qt.Equals, true)
   120  		c.Assert(f, qt.Equals, SuffixInfo{
   121  			Suffix:     suffix,
   122  			FullSuffix: "." + suffix,
   123  		})
   124  		c.Assert(t, qt.Equals, expectedType)
   125  	}
   126  
   127  	check("js", JavascriptType)
   128  	check("json", JSONType)
   129  	check("geojson", geoJSON)
   130  	check("gjson", geoJSON)
   131  }
   132  
   133  func TestFromTypeString(t *testing.T) {
   134  	c := qt.New(t)
   135  	f, err := fromString("text/html")
   136  	c.Assert(err, qt.IsNil)
   137  	c.Assert(f.Type(), qt.Equals, HTMLType.Type())
   138  
   139  	f, err = fromString("application/custom")
   140  	c.Assert(err, qt.IsNil)
   141  	c.Assert(f, qt.Equals, Type{MainType: "application", SubType: "custom", mimeSuffix: ""})
   142  
   143  	f, err = fromString("application/custom+sfx")
   144  	c.Assert(err, qt.IsNil)
   145  	c.Assert(f, qt.Equals, Type{MainType: "application", SubType: "custom", mimeSuffix: "sfx"})
   146  
   147  	_, err = fromString("noslash")
   148  	c.Assert(err, qt.Not(qt.IsNil))
   149  
   150  	f, err = fromString("text/xml; charset=utf-8")
   151  	c.Assert(err, qt.IsNil)
   152  
   153  	c.Assert(f, qt.Equals, Type{MainType: "text", SubType: "xml", mimeSuffix: ""})
   154  }
   155  
   156  func TestFromStringAndExt(t *testing.T) {
   157  	c := qt.New(t)
   158  	f, err := FromStringAndExt("text/html", "html")
   159  	c.Assert(err, qt.IsNil)
   160  	c.Assert(f, qt.Equals, HTMLType)
   161  	f, err = FromStringAndExt("text/html", ".html")
   162  	c.Assert(err, qt.IsNil)
   163  	c.Assert(f, qt.Equals, HTMLType)
   164  }
   165  
   166  // Add a test for the SVG case
   167  // https://github.com/gohugoio/hugo/issues/4920
   168  func TestFromExtensionMultipleSuffixes(t *testing.T) {
   169  	c := qt.New(t)
   170  	tp, si, found := DefaultTypes.GetBySuffix("svg")
   171  	c.Assert(found, qt.Equals, true)
   172  	c.Assert(tp.String(), qt.Equals, "image/svg+xml")
   173  	c.Assert(si.Suffix, qt.Equals, "svg")
   174  	c.Assert(si.FullSuffix, qt.Equals, ".svg")
   175  	c.Assert(tp.FirstSuffix.Suffix, qt.Equals, si.Suffix)
   176  	c.Assert(tp.FirstSuffix.FullSuffix, qt.Equals, si.FullSuffix)
   177  	ftp, found := DefaultTypes.GetByType("image/svg+xml")
   178  	c.Assert(found, qt.Equals, true)
   179  	c.Assert(ftp.String(), qt.Equals, "image/svg+xml")
   180  	c.Assert(found, qt.Equals, true)
   181  }
   182  
   183  func TestFromContent(t *testing.T) {
   184  	c := qt.New(t)
   185  
   186  	files, err := filepath.Glob("./testdata/resource.*")
   187  	c.Assert(err, qt.IsNil)
   188  	mtypes := DefaultTypes
   189  
   190  	for _, filename := range files {
   191  		name := filepath.Base(filename)
   192  		c.Run(name, func(c *qt.C) {
   193  			content, err := ioutil.ReadFile(filename)
   194  			c.Assert(err, qt.IsNil)
   195  			ext := strings.TrimPrefix(paths.Ext(filename), ".")
   196  			var exts []string
   197  			if ext == "jpg" {
   198  				exts = append(exts, "foo", "bar", "jpg")
   199  			} else {
   200  				exts = []string{ext}
   201  			}
   202  			expected, _, found := mtypes.GetFirstBySuffix(ext)
   203  			c.Assert(found, qt.IsTrue)
   204  			got := FromContent(mtypes, exts, content)
   205  			c.Assert(got, qt.Equals, expected)
   206  		})
   207  	}
   208  }
   209  
   210  func TestFromContentFakes(t *testing.T) {
   211  	c := qt.New(t)
   212  
   213  	files, err := filepath.Glob("./testdata/fake.*")
   214  	c.Assert(err, qt.IsNil)
   215  	mtypes := DefaultTypes
   216  
   217  	for _, filename := range files {
   218  		name := filepath.Base(filename)
   219  		c.Run(name, func(c *qt.C) {
   220  			content, err := ioutil.ReadFile(filename)
   221  			c.Assert(err, qt.IsNil)
   222  			ext := strings.TrimPrefix(paths.Ext(filename), ".")
   223  			got := FromContent(mtypes, []string{ext}, content)
   224  			c.Assert(got, qt.Equals, zero)
   225  		})
   226  	}
   227  }
   228  
   229  func TestDecodeTypes(t *testing.T) {
   230  	c := qt.New(t)
   231  
   232  	tests := []struct {
   233  		name        string
   234  		maps        []map[string]interface{}
   235  		shouldError bool
   236  		assert      func(t *testing.T, name string, tt Types)
   237  	}{
   238  		{
   239  			"Redefine JSON",
   240  			[]map[string]interface{}{
   241  				{
   242  					"application/json": map[string]interface{}{
   243  						"suffixes": []string{"jasn"},
   244  					},
   245  				},
   246  			},
   247  			false,
   248  			func(t *testing.T, name string, tt Types) {
   249  				c.Assert(len(tt), qt.Equals, len(DefaultTypes))
   250  				json, si, found := tt.GetBySuffix("jasn")
   251  				c.Assert(found, qt.Equals, true)
   252  				c.Assert(json.String(), qt.Equals, "application/json")
   253  				c.Assert(si.FullSuffix, qt.Equals, ".jasn")
   254  			},
   255  		},
   256  		{
   257  			"MIME suffix in key, multiple file suffixes, custom delimiter",
   258  			[]map[string]interface{}{
   259  				{
   260  					"application/hugo+hg": map[string]interface{}{
   261  						"suffixes":  []string{"hg1", "hG2"},
   262  						"Delimiter": "_",
   263  					},
   264  				},
   265  			},
   266  			false,
   267  			func(t *testing.T, name string, tt Types) {
   268  				c.Assert(len(tt), qt.Equals, len(DefaultTypes)+1)
   269  				hg, si, found := tt.GetBySuffix("hg2")
   270  				c.Assert(found, qt.Equals, true)
   271  				c.Assert(hg.mimeSuffix, qt.Equals, "hg")
   272  				c.Assert(hg.FirstSuffix.Suffix, qt.Equals, "hg1")
   273  				c.Assert(hg.FirstSuffix.FullSuffix, qt.Equals, "_hg1")
   274  				c.Assert(si.Suffix, qt.Equals, "hg2")
   275  				c.Assert(si.FullSuffix, qt.Equals, "_hg2")
   276  				c.Assert(hg.String(), qt.Equals, "application/hugo+hg")
   277  
   278  				_, found = tt.GetByType("application/hugo+hg")
   279  				c.Assert(found, qt.Equals, true)
   280  			},
   281  		},
   282  		{
   283  			"Add custom media type",
   284  			[]map[string]interface{}{
   285  				{
   286  					"text/hugo+hgo": map[string]interface{}{
   287  						"Suffixes": []string{"hgo2"},
   288  					},
   289  				},
   290  			},
   291  			false,
   292  			func(t *testing.T, name string, tp Types) {
   293  				c.Assert(len(tp), qt.Equals, len(DefaultTypes)+1)
   294  				// Make sure we have not broken the default config.
   295  
   296  				_, _, found := tp.GetBySuffix("json")
   297  				c.Assert(found, qt.Equals, true)
   298  
   299  				hugo, _, found := tp.GetBySuffix("hgo2")
   300  				c.Assert(found, qt.Equals, true)
   301  				c.Assert(hugo.String(), qt.Equals, "text/hugo+hgo")
   302  			},
   303  		},
   304  	}
   305  
   306  	for _, test := range tests {
   307  		result, err := DecodeTypes(test.maps...)
   308  		if test.shouldError {
   309  			c.Assert(err, qt.Not(qt.IsNil))
   310  		} else {
   311  			c.Assert(err, qt.IsNil)
   312  			test.assert(t, test.name, result)
   313  		}
   314  	}
   315  }
   316  
   317  func TestToJSON(t *testing.T) {
   318  	c := qt.New(t)
   319  	b, err := json.Marshal(MPEGType)
   320  	c.Assert(err, qt.IsNil)
   321  	c.Assert(string(b), qt.Equals, `{"mainType":"video","subType":"mpeg","delimiter":".","firstSuffix":{"suffix":"mpg","fullSuffix":".mpg"},"type":"video/mpeg","string":"video/mpeg","suffixes":["mpg","mpeg"]}`)
   322  }
   323  
   324  func BenchmarkTypeOps(b *testing.B) {
   325  	mt := MPEGType
   326  	mts := DefaultTypes
   327  	for i := 0; i < b.N; i++ {
   328  		ff := mt.FirstSuffix
   329  		_ = ff.FullSuffix
   330  		_ = mt.IsZero()
   331  		c, err := mt.MarshalJSON()
   332  		if c == nil || err != nil {
   333  			b.Fatal("failed")
   334  		}
   335  		_ = mt.String()
   336  		_ = ff.Suffix
   337  		_ = mt.Suffixes
   338  		_ = mt.Type()
   339  		_ = mts.BySuffix("xml")
   340  		_, _ = mts.GetByMainSubType("application", "xml")
   341  		_, _, _ = mts.GetBySuffix("xml")
   342  		_, _ = mts.GetByType("application")
   343  		_, _, _ = mts.GetFirstBySuffix("xml")
   344  
   345  	}
   346  }