github.com/gohugoio/hugo@v0.88.1/helpers/general_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 helpers
    15  
    16  import (
    17  	"fmt"
    18  	"reflect"
    19  	"strings"
    20  	"testing"
    21  
    22  	"github.com/gohugoio/hugo/config"
    23  
    24  	"github.com/gohugoio/hugo/common/loggers"
    25  
    26  	qt "github.com/frankban/quicktest"
    27  	"github.com/spf13/afero"
    28  )
    29  
    30  func TestResolveMarkup(t *testing.T) {
    31  	c := qt.New(t)
    32  	cfg := config.New()
    33  	spec, err := NewContentSpec(cfg, loggers.NewErrorLogger(), afero.NewMemMapFs())
    34  	c.Assert(err, qt.IsNil)
    35  
    36  	for i, this := range []struct {
    37  		in     string
    38  		expect string
    39  	}{
    40  		{"md", "markdown"},
    41  		{"markdown", "markdown"},
    42  		{"mdown", "markdown"},
    43  		{"asciidocext", "asciidocext"},
    44  		{"adoc", "asciidocext"},
    45  		{"ad", "asciidocext"},
    46  		{"rst", "rst"},
    47  		{"pandoc", "pandoc"},
    48  		{"pdc", "pandoc"},
    49  		{"mmark", "mmark"},
    50  		{"html", "html"},
    51  		{"htm", "html"},
    52  		{"org", "org"},
    53  		{"excel", ""},
    54  	} {
    55  		result := spec.ResolveMarkup(this.in)
    56  		if result != this.expect {
    57  			t.Errorf("[%d] got %s but expected %s", i, result, this.expect)
    58  		}
    59  	}
    60  }
    61  
    62  func TestFirstUpper(t *testing.T) {
    63  	for i, this := range []struct {
    64  		in     string
    65  		expect string
    66  	}{
    67  		{"foo", "Foo"},
    68  		{"foo bar", "Foo bar"},
    69  		{"Foo Bar", "Foo Bar"},
    70  		{"", ""},
    71  		{"å", "Å"},
    72  	} {
    73  		result := FirstUpper(this.in)
    74  		if result != this.expect {
    75  			t.Errorf("[%d] got %s but expected %s", i, result, this.expect)
    76  		}
    77  	}
    78  }
    79  
    80  func TestHasStringsPrefix(t *testing.T) {
    81  	for i, this := range []struct {
    82  		s      []string
    83  		prefix []string
    84  		expect bool
    85  	}{
    86  		{[]string{"a"}, []string{"a"}, true},
    87  		{[]string{}, []string{}, true},
    88  		{[]string{"a", "b", "c"}, []string{"a", "b"}, true},
    89  		{[]string{"d", "a", "b", "c"}, []string{"a", "b"}, false},
    90  		{[]string{"abra", "ca", "dabra"}, []string{"abra", "ca"}, true},
    91  		{[]string{"abra", "ca"}, []string{"abra", "ca", "dabra"}, false},
    92  	} {
    93  		result := HasStringsPrefix(this.s, this.prefix)
    94  		if result != this.expect {
    95  			t.Fatalf("[%d] got %t but expected %t", i, result, this.expect)
    96  		}
    97  	}
    98  }
    99  
   100  func TestHasStringsSuffix(t *testing.T) {
   101  	for i, this := range []struct {
   102  		s      []string
   103  		suffix []string
   104  		expect bool
   105  	}{
   106  		{[]string{"a"}, []string{"a"}, true},
   107  		{[]string{}, []string{}, true},
   108  		{[]string{"a", "b", "c"}, []string{"b", "c"}, true},
   109  		{[]string{"abra", "ca", "dabra"}, []string{"abra", "ca"}, false},
   110  		{[]string{"abra", "ca", "dabra"}, []string{"ca", "dabra"}, true},
   111  	} {
   112  		result := HasStringsSuffix(this.s, this.suffix)
   113  		if result != this.expect {
   114  			t.Fatalf("[%d] got %t but expected %t", i, result, this.expect)
   115  		}
   116  	}
   117  }
   118  
   119  var containsTestText = (`На берегу пустынных волн
   120  Стоял он, дум великих полн,
   121  И вдаль глядел. Пред ним широко
   122  Река неслася; бедный чёлн
   123  По ней стремился одиноко.
   124  По мшистым, топким берегам
   125  Чернели избы здесь и там,
   126  Приют убогого чухонца;
   127  И лес, неведомый лучам
   128  В тумане спрятанного солнца,
   129  Кругом шумел.
   130  
   131  Τη γλώσσα μου έδωσαν ελληνική
   132  το σπίτι φτωχικό στις αμμουδιές του Ομήρου.
   133  Μονάχη έγνοια η γλώσσα μου στις αμμουδιές του Ομήρου.
   134  
   135  από το Άξιον Εστί
   136  του Οδυσσέα Ελύτη
   137  
   138  Sîne klâwen durh die wolken sint geslagen,
   139  er stîget ûf mit grôzer kraft,
   140  ich sih in grâwen tägelîch als er wil tagen,
   141  den tac, der im geselleschaft
   142  erwenden wil, dem werden man,
   143  den ich mit sorgen în verliez.
   144  ich bringe in hinnen, ob ich kan.
   145  sîn vil manegiu tugent michz leisten hiez.
   146  `)
   147  
   148  var containsBenchTestData = []struct {
   149  	v1     string
   150  	v2     []byte
   151  	expect bool
   152  }{
   153  	{"abc", []byte("a"), true},
   154  	{"abc", []byte("b"), true},
   155  	{"abcdefg", []byte("efg"), true},
   156  	{"abc", []byte("d"), false},
   157  	{containsTestText, []byte("стремился"), true},
   158  	{containsTestText, []byte(containsTestText[10:80]), true},
   159  	{containsTestText, []byte(containsTestText[100:111]), true},
   160  	{containsTestText, []byte(containsTestText[len(containsTestText)-100 : len(containsTestText)-10]), true},
   161  	{containsTestText, []byte(containsTestText[len(containsTestText)-20:]), true},
   162  	{containsTestText, []byte("notfound"), false},
   163  }
   164  
   165  // some corner cases
   166  var containsAdditionalTestData = []struct {
   167  	v1     string
   168  	v2     []byte
   169  	expect bool
   170  }{
   171  	{"", nil, false},
   172  	{"", []byte("a"), false},
   173  	{"a", []byte(""), false},
   174  	{"", []byte(""), false},
   175  }
   176  
   177  func TestSliceToLower(t *testing.T) {
   178  	t.Parallel()
   179  	tests := []struct {
   180  		value    []string
   181  		expected []string
   182  	}{
   183  		{[]string{"a", "b", "c"}, []string{"a", "b", "c"}},
   184  		{[]string{"a", "B", "c"}, []string{"a", "b", "c"}},
   185  		{[]string{"A", "B", "C"}, []string{"a", "b", "c"}},
   186  	}
   187  
   188  	for _, test := range tests {
   189  		res := SliceToLower(test.value)
   190  		for i, val := range res {
   191  			if val != test.expected[i] {
   192  				t.Errorf("Case mismatch. Expected %s, got %s", test.expected[i], res[i])
   193  			}
   194  		}
   195  	}
   196  }
   197  
   198  func TestReaderContains(t *testing.T) {
   199  	c := qt.New(t)
   200  	for i, this := range append(containsBenchTestData, containsAdditionalTestData...) {
   201  		result := ReaderContains(strings.NewReader(this.v1), this.v2)
   202  		if result != this.expect {
   203  			t.Errorf("[%d] got %t but expected %t", i, result, this.expect)
   204  		}
   205  	}
   206  
   207  	c.Assert(ReaderContains(nil, []byte("a")), qt.Equals, false)
   208  	c.Assert(ReaderContains(nil, nil), qt.Equals, false)
   209  }
   210  
   211  func TestGetTitleFunc(t *testing.T) {
   212  	title := "somewhere over the rainbow"
   213  	c := qt.New(t)
   214  
   215  	c.Assert(GetTitleFunc("go")(title), qt.Equals, "Somewhere Over The Rainbow")
   216  	c.Assert(GetTitleFunc("chicago")(title), qt.Equals, "Somewhere over the Rainbow")
   217  	c.Assert(GetTitleFunc("Chicago")(title), qt.Equals, "Somewhere over the Rainbow")
   218  	c.Assert(GetTitleFunc("ap")(title), qt.Equals, "Somewhere Over the Rainbow")
   219  	c.Assert(GetTitleFunc("ap")(title), qt.Equals, "Somewhere Over the Rainbow")
   220  	c.Assert(GetTitleFunc("")(title), qt.Equals, "Somewhere Over the Rainbow")
   221  	c.Assert(GetTitleFunc("unknown")(title), qt.Equals, "Somewhere Over the Rainbow")
   222  }
   223  
   224  func BenchmarkReaderContains(b *testing.B) {
   225  	b.ResetTimer()
   226  	for i := 0; i < b.N; i++ {
   227  		for i, this := range containsBenchTestData {
   228  			result := ReaderContains(strings.NewReader(this.v1), this.v2)
   229  			if result != this.expect {
   230  				b.Errorf("[%d] got %t but expected %t", i, result, this.expect)
   231  			}
   232  		}
   233  	}
   234  }
   235  
   236  func TestUniqueStrings(t *testing.T) {
   237  	in := []string{"a", "b", "a", "b", "c", "", "a", "", "d"}
   238  	output := UniqueStrings(in)
   239  	expected := []string{"a", "b", "c", "", "d"}
   240  	if !reflect.DeepEqual(output, expected) {
   241  		t.Errorf("Expected %#v, got %#v\n", expected, output)
   242  	}
   243  }
   244  
   245  func TestUniqueStringsReuse(t *testing.T) {
   246  	in := []string{"a", "b", "a", "b", "c", "", "a", "", "d"}
   247  	output := UniqueStringsReuse(in)
   248  	expected := []string{"a", "b", "c", "", "d"}
   249  	if !reflect.DeepEqual(output, expected) {
   250  		t.Errorf("Expected %#v, got %#v\n", expected, output)
   251  	}
   252  }
   253  
   254  func TestUniqueStringsSorted(t *testing.T) {
   255  	c := qt.New(t)
   256  	in := []string{"a", "a", "b", "c", "b", "", "a", "", "d"}
   257  	output := UniqueStringsSorted(in)
   258  	expected := []string{"", "a", "b", "c", "d"}
   259  	c.Assert(output, qt.DeepEquals, expected)
   260  	c.Assert(UniqueStringsSorted(nil), qt.IsNil)
   261  }
   262  
   263  func TestFindAvailablePort(t *testing.T) {
   264  	c := qt.New(t)
   265  	addr, err := FindAvailablePort()
   266  	c.Assert(err, qt.IsNil)
   267  	c.Assert(addr, qt.Not(qt.IsNil))
   268  	c.Assert(addr.Port > 0, qt.Equals, true)
   269  }
   270  
   271  func TestFastMD5FromFile(t *testing.T) {
   272  	fs := afero.NewMemMapFs()
   273  
   274  	if err := afero.WriteFile(fs, "small.txt", []byte("abc"), 0777); err != nil {
   275  		t.Fatal(err)
   276  	}
   277  
   278  	if err := afero.WriteFile(fs, "small2.txt", []byte("abd"), 0777); err != nil {
   279  		t.Fatal(err)
   280  	}
   281  
   282  	if err := afero.WriteFile(fs, "bigger.txt", []byte(strings.Repeat("a bc d e", 100)), 0777); err != nil {
   283  		t.Fatal(err)
   284  	}
   285  
   286  	if err := afero.WriteFile(fs, "bigger2.txt", []byte(strings.Repeat("c d e f g", 100)), 0777); err != nil {
   287  		t.Fatal(err)
   288  	}
   289  
   290  	c := qt.New(t)
   291  
   292  	sf1, err := fs.Open("small.txt")
   293  	c.Assert(err, qt.IsNil)
   294  	sf2, err := fs.Open("small2.txt")
   295  	c.Assert(err, qt.IsNil)
   296  
   297  	bf1, err := fs.Open("bigger.txt")
   298  	c.Assert(err, qt.IsNil)
   299  	bf2, err := fs.Open("bigger2.txt")
   300  	c.Assert(err, qt.IsNil)
   301  
   302  	defer sf1.Close()
   303  	defer sf2.Close()
   304  	defer bf1.Close()
   305  	defer bf2.Close()
   306  
   307  	m1, err := MD5FromFileFast(sf1)
   308  	c.Assert(err, qt.IsNil)
   309  	c.Assert(m1, qt.Equals, "e9c8989b64b71a88b4efb66ad05eea96")
   310  
   311  	m2, err := MD5FromFileFast(sf2)
   312  	c.Assert(err, qt.IsNil)
   313  	c.Assert(m2, qt.Not(qt.Equals), m1)
   314  
   315  	m3, err := MD5FromFileFast(bf1)
   316  	c.Assert(err, qt.IsNil)
   317  	c.Assert(m3, qt.Not(qt.Equals), m2)
   318  
   319  	m4, err := MD5FromFileFast(bf2)
   320  	c.Assert(err, qt.IsNil)
   321  	c.Assert(m4, qt.Not(qt.Equals), m3)
   322  
   323  	m5, err := MD5FromReader(bf2)
   324  	c.Assert(err, qt.IsNil)
   325  	c.Assert(m5, qt.Not(qt.Equals), m4)
   326  }
   327  
   328  func BenchmarkMD5FromFileFast(b *testing.B) {
   329  	fs := afero.NewMemMapFs()
   330  
   331  	for _, full := range []bool{false, true} {
   332  		b.Run(fmt.Sprintf("full=%t", full), func(b *testing.B) {
   333  			for i := 0; i < b.N; i++ {
   334  				b.StopTimer()
   335  				if err := afero.WriteFile(fs, "file.txt", []byte(strings.Repeat("1234567890", 2000)), 0777); err != nil {
   336  					b.Fatal(err)
   337  				}
   338  				f, err := fs.Open("file.txt")
   339  				if err != nil {
   340  					b.Fatal(err)
   341  				}
   342  				b.StartTimer()
   343  				if full {
   344  					if _, err := MD5FromReader(f); err != nil {
   345  						b.Fatal(err)
   346  					}
   347  				} else {
   348  					if _, err := MD5FromFileFast(f); err != nil {
   349  						b.Fatal(err)
   350  					}
   351  				}
   352  				f.Close()
   353  			}
   354  		})
   355  	}
   356  }
   357  
   358  func BenchmarkUniqueStrings(b *testing.B) {
   359  	input := []string{"a", "b", "d", "e", "d", "h", "a", "i"}
   360  
   361  	b.Run("Safe", func(b *testing.B) {
   362  		for i := 0; i < b.N; i++ {
   363  			result := UniqueStrings(input)
   364  			if len(result) != 6 {
   365  				b.Fatal(fmt.Sprintf("invalid count: %d", len(result)))
   366  			}
   367  		}
   368  	})
   369  
   370  	b.Run("Reuse slice", func(b *testing.B) {
   371  		b.StopTimer()
   372  		inputs := make([][]string, b.N)
   373  		for i := 0; i < b.N; i++ {
   374  			inputc := make([]string, len(input))
   375  			copy(inputc, input)
   376  			inputs[i] = inputc
   377  		}
   378  		b.StartTimer()
   379  		for i := 0; i < b.N; i++ {
   380  			inputc := inputs[i]
   381  
   382  			result := UniqueStringsReuse(inputc)
   383  			if len(result) != 6 {
   384  				b.Fatal(fmt.Sprintf("invalid count: %d", len(result)))
   385  			}
   386  		}
   387  	})
   388  
   389  	b.Run("Reuse slice sorted", func(b *testing.B) {
   390  		b.StopTimer()
   391  		inputs := make([][]string, b.N)
   392  		for i := 0; i < b.N; i++ {
   393  			inputc := make([]string, len(input))
   394  			copy(inputc, input)
   395  			inputs[i] = inputc
   396  		}
   397  		b.StartTimer()
   398  		for i := 0; i < b.N; i++ {
   399  			inputc := inputs[i]
   400  
   401  			result := UniqueStringsSorted(inputc)
   402  			if len(result) != 6 {
   403  				b.Fatal(fmt.Sprintf("invalid count: %d", len(result)))
   404  			}
   405  		}
   406  	})
   407  }
   408  
   409  func TestHashString(t *testing.T) {
   410  	c := qt.New(t)
   411  
   412  	c.Assert(HashString("a", "b"), qt.Equals, "2712570657419664240")
   413  	c.Assert(HashString("ab"), qt.Equals, "590647783936702392")
   414  }