hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

general_test.go (12837B)

    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 	"time"
   22 
   23 	"github.com/gohugoio/hugo/common/loggers"
   24 	"github.com/gohugoio/hugo/config"
   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.NewWithTestDefaults()
   33 	spec, err := NewContentSpec(cfg, loggers.NewErrorLogger(), afero.NewMemMapFs(), nil)
   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 		{"html", "html"},
   50 		{"htm", "html"},
   51 		{"org", "org"},
   52 		{"excel", ""},
   53 	} {
   54 		result := spec.ResolveMarkup(this.in)
   55 		if result != this.expect {
   56 			t.Errorf("[%d] got %s but expected %s", i, result, this.expect)
   57 		}
   58 	}
   59 }
   60 
   61 func TestDistinctLoggerDoesNotLockOnWarningPanic(t *testing.T) {
   62 	// Testing to make sure logger mutex doesn't lock if warnings cause panics.
   63 	// func Warnf() of DistinctLogger is defined in general.go
   64 	l := NewDistinctLogger(loggers.NewWarningLogger())
   65 
   66 	// Set PanicOnWarning to true to reproduce issue 9380
   67 	// Ensure global variable loggers.PanicOnWarning is reset to old value after test
   68 	if loggers.PanicOnWarning == false {
   69 		loggers.PanicOnWarning = true
   70 		defer func() {
   71 			loggers.PanicOnWarning = false
   72 		}()
   73 	}
   74 
   75 	// Establish timeout in case a lock occurs:
   76 	timeIsUp := make(chan bool)
   77 	timeOutSeconds := 1
   78 	go func() {
   79 		time.Sleep(time.Second * time.Duration(timeOutSeconds))
   80 		timeIsUp <- true
   81 	}()
   82 
   83 	// Attempt to run multiple logging threads in parallel
   84 	counterC := make(chan int)
   85 	goroutines := 5
   86 
   87 	for i := 0; i < goroutines; i++ {
   88 		go func() {
   89 			defer func() {
   90 				// Intentional panic successfully recovered - notify counter channel
   91 				recover()
   92 				counterC <- 1
   93 			}()
   94 
   95 			l.Warnf("Placeholder template message: %v", "In this test, logging a warning causes a panic.")
   96 		}()
   97 	}
   98 
   99 	// All goroutines should complete before timeout
  100 	var counter int
  101 	for {
  102 		select {
  103 		case <-counterC:
  104 			counter++
  105 			if counter == goroutines {
  106 				return
  107 			}
  108 		case <-timeIsUp:
  109 			t.Errorf("Unable to log warnings with --panicOnWarning within alloted time of: %v seconds. Investigate possible mutex locking on panic in distinct warning logger.", timeOutSeconds)
  110 			return
  111 		}
  112 	}
  113 }
  114 
  115 func TestFirstUpper(t *testing.T) {
  116 	for i, this := range []struct {
  117 		in     string
  118 		expect string
  119 	}{
  120 		{"foo", "Foo"},
  121 		{"foo bar", "Foo bar"},
  122 		{"Foo Bar", "Foo Bar"},
  123 		{"", ""},
  124 		{"å", "Å"},
  125 	} {
  126 		result := FirstUpper(this.in)
  127 		if result != this.expect {
  128 			t.Errorf("[%d] got %s but expected %s", i, result, this.expect)
  129 		}
  130 	}
  131 }
  132 
  133 func TestHasStringsPrefix(t *testing.T) {
  134 	for i, this := range []struct {
  135 		s      []string
  136 		prefix []string
  137 		expect bool
  138 	}{
  139 		{[]string{"a"}, []string{"a"}, true},
  140 		{[]string{}, []string{}, true},
  141 		{[]string{"a", "b", "c"}, []string{"a", "b"}, true},
  142 		{[]string{"d", "a", "b", "c"}, []string{"a", "b"}, false},
  143 		{[]string{"abra", "ca", "dabra"}, []string{"abra", "ca"}, true},
  144 		{[]string{"abra", "ca"}, []string{"abra", "ca", "dabra"}, false},
  145 	} {
  146 		result := HasStringsPrefix(this.s, this.prefix)
  147 		if result != this.expect {
  148 			t.Fatalf("[%d] got %t but expected %t", i, result, this.expect)
  149 		}
  150 	}
  151 }
  152 
  153 func TestHasStringsSuffix(t *testing.T) {
  154 	for i, this := range []struct {
  155 		s      []string
  156 		suffix []string
  157 		expect bool
  158 	}{
  159 		{[]string{"a"}, []string{"a"}, true},
  160 		{[]string{}, []string{}, true},
  161 		{[]string{"a", "b", "c"}, []string{"b", "c"}, true},
  162 		{[]string{"abra", "ca", "dabra"}, []string{"abra", "ca"}, false},
  163 		{[]string{"abra", "ca", "dabra"}, []string{"ca", "dabra"}, true},
  164 	} {
  165 		result := HasStringsSuffix(this.s, this.suffix)
  166 		if result != this.expect {
  167 			t.Fatalf("[%d] got %t but expected %t", i, result, this.expect)
  168 		}
  169 	}
  170 }
  171 
  172 var containsTestText = (`На берегу пустынных волн
  173 Стоял он, дум великих полн,
  174 И вдаль глядел. Пред ним широко
  175 Река неслася; бедный чёлн
  176 По ней стремился одиноко.
  177 По мшистым, топким берегам
  178 Чернели избы здесь и там,
  179 Приют убогого чухонца;
  180 И лес, неведомый лучам
  181 В тумане спрятанного солнца,
  182 Кругом шумел.
  183 
  184 Τη γλώσσα μου έδωσαν ελληνική
  185 το σπίτι φτωχικό στις αμμουδιές του Ομήρου.
  186 Μονάχη έγνοια η γλώσσα μου στις αμμουδιές του Ομήρου.
  187 
  188 από το Άξιον Εστί
  189 του Οδυσσέα Ελύτη
  190 
  191 Sîne klâwen durh die wolken sint geslagen,
  192 er stîget ûf mit grôzer kraft,
  193 ich sih in grâwen tägelîch als er wil tagen,
  194 den tac, der im geselleschaft
  195 erwenden wil, dem werden man,
  196 den ich mit sorgen în verliez.
  197 ich bringe in hinnen, ob ich kan.
  198 sîn vil manegiu tugent michz leisten hiez.
  199 `)
  200 
  201 var containsBenchTestData = []struct {
  202 	v1     string
  203 	v2     []byte
  204 	expect bool
  205 }{
  206 	{"abc", []byte("a"), true},
  207 	{"abc", []byte("b"), true},
  208 	{"abcdefg", []byte("efg"), true},
  209 	{"abc", []byte("d"), false},
  210 	{containsTestText, []byte("стремился"), true},
  211 	{containsTestText, []byte(containsTestText[10:80]), true},
  212 	{containsTestText, []byte(containsTestText[100:111]), true},
  213 	{containsTestText, []byte(containsTestText[len(containsTestText)-100 : len(containsTestText)-10]), true},
  214 	{containsTestText, []byte(containsTestText[len(containsTestText)-20:]), true},
  215 	{containsTestText, []byte("notfound"), false},
  216 }
  217 
  218 // some corner cases
  219 var containsAdditionalTestData = []struct {
  220 	v1     string
  221 	v2     []byte
  222 	expect bool
  223 }{
  224 	{"", nil, false},
  225 	{"", []byte("a"), false},
  226 	{"a", []byte(""), false},
  227 	{"", []byte(""), false},
  228 }
  229 
  230 func TestSliceToLower(t *testing.T) {
  231 	t.Parallel()
  232 	tests := []struct {
  233 		value    []string
  234 		expected []string
  235 	}{
  236 		{[]string{"a", "b", "c"}, []string{"a", "b", "c"}},
  237 		{[]string{"a", "B", "c"}, []string{"a", "b", "c"}},
  238 		{[]string{"A", "B", "C"}, []string{"a", "b", "c"}},
  239 	}
  240 
  241 	for _, test := range tests {
  242 		res := SliceToLower(test.value)
  243 		for i, val := range res {
  244 			if val != test.expected[i] {
  245 				t.Errorf("Case mismatch. Expected %s, got %s", test.expected[i], res[i])
  246 			}
  247 		}
  248 	}
  249 }
  250 
  251 func TestReaderContains(t *testing.T) {
  252 	c := qt.New(t)
  253 	for i, this := range append(containsBenchTestData, containsAdditionalTestData...) {
  254 		result := ReaderContains(strings.NewReader(this.v1), this.v2)
  255 		if result != this.expect {
  256 			t.Errorf("[%d] got %t but expected %t", i, result, this.expect)
  257 		}
  258 	}
  259 
  260 	c.Assert(ReaderContains(nil, []byte("a")), qt.Equals, false)
  261 	c.Assert(ReaderContains(nil, nil), qt.Equals, false)
  262 }
  263 
  264 func TestGetTitleFunc(t *testing.T) {
  265 	title := "somewhere over the rainbow"
  266 	c := qt.New(t)
  267 
  268 	c.Assert(GetTitleFunc("go")(title), qt.Equals, "Somewhere Over The Rainbow")
  269 	c.Assert(GetTitleFunc("chicago")(title), qt.Equals, "Somewhere over the Rainbow")
  270 	c.Assert(GetTitleFunc("Chicago")(title), qt.Equals, "Somewhere over the Rainbow")
  271 	c.Assert(GetTitleFunc("ap")(title), qt.Equals, "Somewhere Over the Rainbow")
  272 	c.Assert(GetTitleFunc("ap")(title), qt.Equals, "Somewhere Over the Rainbow")
  273 	c.Assert(GetTitleFunc("")(title), qt.Equals, "Somewhere Over the Rainbow")
  274 	c.Assert(GetTitleFunc("unknown")(title), qt.Equals, "Somewhere Over the Rainbow")
  275 }
  276 
  277 func BenchmarkReaderContains(b *testing.B) {
  278 	b.ResetTimer()
  279 	for i := 0; i < b.N; i++ {
  280 		for i, this := range containsBenchTestData {
  281 			result := ReaderContains(strings.NewReader(this.v1), this.v2)
  282 			if result != this.expect {
  283 				b.Errorf("[%d] got %t but expected %t", i, result, this.expect)
  284 			}
  285 		}
  286 	}
  287 }
  288 
  289 func TestUniqueStrings(t *testing.T) {
  290 	in := []string{"a", "b", "a", "b", "c", "", "a", "", "d"}
  291 	output := UniqueStrings(in)
  292 	expected := []string{"a", "b", "c", "", "d"}
  293 	if !reflect.DeepEqual(output, expected) {
  294 		t.Errorf("Expected %#v, got %#v\n", expected, output)
  295 	}
  296 }
  297 
  298 func TestUniqueStringsReuse(t *testing.T) {
  299 	in := []string{"a", "b", "a", "b", "c", "", "a", "", "d"}
  300 	output := UniqueStringsReuse(in)
  301 	expected := []string{"a", "b", "c", "", "d"}
  302 	if !reflect.DeepEqual(output, expected) {
  303 		t.Errorf("Expected %#v, got %#v\n", expected, output)
  304 	}
  305 }
  306 
  307 func TestUniqueStringsSorted(t *testing.T) {
  308 	c := qt.New(t)
  309 	in := []string{"a", "a", "b", "c", "b", "", "a", "", "d"}
  310 	output := UniqueStringsSorted(in)
  311 	expected := []string{"", "a", "b", "c", "d"}
  312 	c.Assert(output, qt.DeepEquals, expected)
  313 	c.Assert(UniqueStringsSorted(nil), qt.IsNil)
  314 }
  315 
  316 func TestFindAvailablePort(t *testing.T) {
  317 	c := qt.New(t)
  318 	addr, err := FindAvailablePort()
  319 	c.Assert(err, qt.IsNil)
  320 	c.Assert(addr, qt.Not(qt.IsNil))
  321 	c.Assert(addr.Port > 0, qt.Equals, true)
  322 }
  323 
  324 func TestFastMD5FromFile(t *testing.T) {
  325 	fs := afero.NewMemMapFs()
  326 
  327 	if err := afero.WriteFile(fs, "small.txt", []byte("abc"), 0777); err != nil {
  328 		t.Fatal(err)
  329 	}
  330 
  331 	if err := afero.WriteFile(fs, "small2.txt", []byte("abd"), 0777); err != nil {
  332 		t.Fatal(err)
  333 	}
  334 
  335 	if err := afero.WriteFile(fs, "bigger.txt", []byte(strings.Repeat("a bc d e", 100)), 0777); err != nil {
  336 		t.Fatal(err)
  337 	}
  338 
  339 	if err := afero.WriteFile(fs, "bigger2.txt", []byte(strings.Repeat("c d e f g", 100)), 0777); err != nil {
  340 		t.Fatal(err)
  341 	}
  342 
  343 	c := qt.New(t)
  344 
  345 	sf1, err := fs.Open("small.txt")
  346 	c.Assert(err, qt.IsNil)
  347 	sf2, err := fs.Open("small2.txt")
  348 	c.Assert(err, qt.IsNil)
  349 
  350 	bf1, err := fs.Open("bigger.txt")
  351 	c.Assert(err, qt.IsNil)
  352 	bf2, err := fs.Open("bigger2.txt")
  353 	c.Assert(err, qt.IsNil)
  354 
  355 	defer sf1.Close()
  356 	defer sf2.Close()
  357 	defer bf1.Close()
  358 	defer bf2.Close()
  359 
  360 	m1, err := MD5FromFileFast(sf1)
  361 	c.Assert(err, qt.IsNil)
  362 	c.Assert(m1, qt.Equals, "e9c8989b64b71a88b4efb66ad05eea96")
  363 
  364 	m2, err := MD5FromFileFast(sf2)
  365 	c.Assert(err, qt.IsNil)
  366 	c.Assert(m2, qt.Not(qt.Equals), m1)
  367 
  368 	m3, err := MD5FromFileFast(bf1)
  369 	c.Assert(err, qt.IsNil)
  370 	c.Assert(m3, qt.Not(qt.Equals), m2)
  371 
  372 	m4, err := MD5FromFileFast(bf2)
  373 	c.Assert(err, qt.IsNil)
  374 	c.Assert(m4, qt.Not(qt.Equals), m3)
  375 
  376 	m5, err := MD5FromReader(bf2)
  377 	c.Assert(err, qt.IsNil)
  378 	c.Assert(m5, qt.Not(qt.Equals), m4)
  379 }
  380 
  381 func BenchmarkMD5FromFileFast(b *testing.B) {
  382 	fs := afero.NewMemMapFs()
  383 
  384 	for _, full := range []bool{false, true} {
  385 		b.Run(fmt.Sprintf("full=%t", full), func(b *testing.B) {
  386 			for i := 0; i < b.N; i++ {
  387 				b.StopTimer()
  388 				if err := afero.WriteFile(fs, "file.txt", []byte(strings.Repeat("1234567890", 2000)), 0777); err != nil {
  389 					b.Fatal(err)
  390 				}
  391 				f, err := fs.Open("file.txt")
  392 				if err != nil {
  393 					b.Fatal(err)
  394 				}
  395 				b.StartTimer()
  396 				if full {
  397 					if _, err := MD5FromReader(f); err != nil {
  398 						b.Fatal(err)
  399 					}
  400 				} else {
  401 					if _, err := MD5FromFileFast(f); err != nil {
  402 						b.Fatal(err)
  403 					}
  404 				}
  405 				f.Close()
  406 			}
  407 		})
  408 	}
  409 }
  410 
  411 func BenchmarkUniqueStrings(b *testing.B) {
  412 	input := []string{"a", "b", "d", "e", "d", "h", "a", "i"}
  413 
  414 	b.Run("Safe", func(b *testing.B) {
  415 		for i := 0; i < b.N; i++ {
  416 			result := UniqueStrings(input)
  417 			if len(result) != 6 {
  418 				b.Fatal(fmt.Sprintf("invalid count: %d", len(result)))
  419 			}
  420 		}
  421 	})
  422 
  423 	b.Run("Reuse slice", func(b *testing.B) {
  424 		b.StopTimer()
  425 		inputs := make([][]string, b.N)
  426 		for i := 0; i < b.N; i++ {
  427 			inputc := make([]string, len(input))
  428 			copy(inputc, input)
  429 			inputs[i] = inputc
  430 		}
  431 		b.StartTimer()
  432 		for i := 0; i < b.N; i++ {
  433 			inputc := inputs[i]
  434 
  435 			result := UniqueStringsReuse(inputc)
  436 			if len(result) != 6 {
  437 				b.Fatal(fmt.Sprintf("invalid count: %d", len(result)))
  438 			}
  439 		}
  440 	})
  441 
  442 	b.Run("Reuse slice sorted", func(b *testing.B) {
  443 		b.StopTimer()
  444 		inputs := make([][]string, b.N)
  445 		for i := 0; i < b.N; i++ {
  446 			inputc := make([]string, len(input))
  447 			copy(inputc, input)
  448 			inputs[i] = inputc
  449 		}
  450 		b.StartTimer()
  451 		for i := 0; i < b.N; i++ {
  452 			inputc := inputs[i]
  453 
  454 			result := UniqueStringsSorted(inputc)
  455 			if len(result) != 6 {
  456 				b.Fatal(fmt.Sprintf("invalid count: %d", len(result)))
  457 			}
  458 		}
  459 	})
  460 }
  461 
  462 func TestHashString(t *testing.T) {
  463 	c := qt.New(t)
  464 
  465 	c.Assert(HashString("a", "b"), qt.Equals, "2712570657419664240")
  466 	c.Assert(HashString("ab"), qt.Equals, "590647783936702392")
  467 }