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 }