github.com/jbramsden/hugo@v0.47.1/helpers/path_test.go (about)

     1  // Copyright 2015 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  	"io/ioutil"
    19  	"os"
    20  	"path/filepath"
    21  	"reflect"
    22  	"runtime"
    23  	"strconv"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/gohugoio/hugo/langs"
    29  
    30  	"github.com/stretchr/testify/require"
    31  
    32  	"github.com/stretchr/testify/assert"
    33  
    34  	"github.com/gohugoio/hugo/hugofs"
    35  	"github.com/spf13/afero"
    36  	"github.com/spf13/viper"
    37  )
    38  
    39  func TestMakePath(t *testing.T) {
    40  	tests := []struct {
    41  		input         string
    42  		expected      string
    43  		removeAccents bool
    44  	}{
    45  		{"  Foo bar  ", "Foo-bar", true},
    46  		{"Foo.Bar/foo_Bar-Foo", "Foo.Bar/foo_Bar-Foo", true},
    47  		{"fOO,bar:foobAR", "fOObarfoobAR", true},
    48  		{"FOo/BaR.html", "FOo/BaR.html", true},
    49  		{"трям/трям", "трям/трям", true},
    50  		{"은행", "은행", true},
    51  		{"Банковский кассир", "Банковскии-кассир", true},
    52  		// Issue #1488
    53  		{"संस्कृत", "संस्कृत", false},
    54  		{"a%C3%B1ame", "a%C3%B1ame", false},         // Issue #1292
    55  		{"this+is+a+test", "this+is+a+test", false}, // Issue #1290
    56  		{"~foo", "~foo", false},                     // Issue #2177
    57  
    58  	}
    59  
    60  	for _, test := range tests {
    61  		v := newTestCfg()
    62  		v.Set("removePathAccents", test.removeAccents)
    63  
    64  		l := langs.NewDefaultLanguage(v)
    65  		p, err := NewPathSpec(hugofs.NewMem(v), l)
    66  		require.NoError(t, err)
    67  
    68  		output := p.MakePath(test.input)
    69  		if output != test.expected {
    70  			t.Errorf("Expected %#v, got %#v\n", test.expected, output)
    71  		}
    72  	}
    73  }
    74  
    75  func TestMakePathSanitized(t *testing.T) {
    76  	v := viper.New()
    77  	v.Set("contentDir", "content")
    78  	v.Set("dataDir", "data")
    79  	v.Set("i18nDir", "i18n")
    80  	v.Set("layoutDir", "layouts")
    81  	v.Set("assetDir", "assets")
    82  	v.Set("resourceDir", "resources")
    83  	v.Set("publishDir", "public")
    84  	v.Set("archetypeDir", "archetypes")
    85  
    86  	l := langs.NewDefaultLanguage(v)
    87  	p, _ := NewPathSpec(hugofs.NewMem(v), l)
    88  
    89  	tests := []struct {
    90  		input    string
    91  		expected string
    92  	}{
    93  		{"  FOO bar  ", "foo-bar"},
    94  		{"Foo.Bar/fOO_bAr-Foo", "foo.bar/foo_bar-foo"},
    95  		{"FOO,bar:FooBar", "foobarfoobar"},
    96  		{"foo/BAR.HTML", "foo/bar.html"},
    97  		{"трям/трям", "трям/трям"},
    98  		{"은행", "은행"},
    99  	}
   100  
   101  	for _, test := range tests {
   102  		output := p.MakePathSanitized(test.input)
   103  		if output != test.expected {
   104  			t.Errorf("Expected %#v, got %#v\n", test.expected, output)
   105  		}
   106  	}
   107  }
   108  
   109  func TestMakePathSanitizedDisablePathToLower(t *testing.T) {
   110  	v := newTestCfg()
   111  
   112  	v.Set("disablePathToLower", true)
   113  
   114  	l := langs.NewDefaultLanguage(v)
   115  	p, _ := NewPathSpec(hugofs.NewMem(v), l)
   116  
   117  	tests := []struct {
   118  		input    string
   119  		expected string
   120  	}{
   121  		{"  FOO bar  ", "FOO-bar"},
   122  		{"Foo.Bar/fOO_bAr-Foo", "Foo.Bar/fOO_bAr-Foo"},
   123  		{"FOO,bar:FooBar", "FOObarFooBar"},
   124  		{"foo/BAR.HTML", "foo/BAR.HTML"},
   125  		{"трям/трям", "трям/трям"},
   126  		{"은행", "은행"},
   127  	}
   128  
   129  	for _, test := range tests {
   130  		output := p.MakePathSanitized(test.input)
   131  		if output != test.expected {
   132  			t.Errorf("Expected %#v, got %#v\n", test.expected, output)
   133  		}
   134  	}
   135  }
   136  
   137  func TestGetRelativePath(t *testing.T) {
   138  	tests := []struct {
   139  		path   string
   140  		base   string
   141  		expect interface{}
   142  	}{
   143  		{filepath.FromSlash("/a/b"), filepath.FromSlash("/a"), filepath.FromSlash("b")},
   144  		{filepath.FromSlash("/a/b/c/"), filepath.FromSlash("/a"), filepath.FromSlash("b/c/")},
   145  		{filepath.FromSlash("/c"), filepath.FromSlash("/a/b"), filepath.FromSlash("../../c")},
   146  		{filepath.FromSlash("/c"), "", false},
   147  	}
   148  	for i, this := range tests {
   149  		// ultimately a fancy wrapper around filepath.Rel
   150  		result, err := GetRelativePath(this.path, this.base)
   151  
   152  		if b, ok := this.expect.(bool); ok && !b {
   153  			if err == nil {
   154  				t.Errorf("[%d] GetRelativePath didn't return an expected error", i)
   155  			}
   156  		} else {
   157  			if err != nil {
   158  				t.Errorf("[%d] GetRelativePath failed: %s", i, err)
   159  				continue
   160  			}
   161  			if result != this.expect {
   162  				t.Errorf("[%d] GetRelativePath got %v but expected %v", i, result, this.expect)
   163  			}
   164  		}
   165  
   166  	}
   167  }
   168  
   169  func TestGetRealPath(t *testing.T) {
   170  	if runtime.GOOS == "windows" && os.Getenv("CI") == "" {
   171  		t.Skip("Skip TestGetRealPath as os.Symlink needs administrator rights on Windows")
   172  	}
   173  
   174  	d1, err := ioutil.TempDir("", "d1")
   175  	defer os.Remove(d1)
   176  	fs := afero.NewOsFs()
   177  
   178  	rp1, err := GetRealPath(fs, d1)
   179  	require.NoError(t, err)
   180  	assert.Equal(t, d1, rp1)
   181  
   182  	sym := filepath.Join(os.TempDir(), "d1sym")
   183  	err = os.Symlink(d1, sym)
   184  	require.NoError(t, err)
   185  	defer os.Remove(sym)
   186  
   187  	rp2, err := GetRealPath(fs, sym)
   188  	require.NoError(t, err)
   189  
   190  	// On OS X, the temp folder is itself a symbolic link (to /private...)
   191  	// This has to do for now.
   192  	assert.True(t, strings.HasSuffix(rp2, d1))
   193  
   194  }
   195  
   196  func TestMakePathRelative(t *testing.T) {
   197  	type test struct {
   198  		inPath, path1, path2, output string
   199  	}
   200  
   201  	data := []test{
   202  		{"/abc/bcd/ab.css", "/abc/bcd", "/bbc/bcd", "/ab.css"},
   203  		{"/abc/bcd/ab.css", "/abcd/bcd", "/abc/bcd", "/ab.css"},
   204  	}
   205  
   206  	for i, d := range data {
   207  		output, _ := makePathRelative(d.inPath, d.path1, d.path2)
   208  		if d.output != output {
   209  			t.Errorf("Test #%d failed. Expected %q got %q", i, d.output, output)
   210  		}
   211  	}
   212  	_, error := makePathRelative("a/b/c.ss", "/a/c", "/d/c", "/e/f")
   213  
   214  	if error == nil {
   215  		t.Errorf("Test failed, expected error")
   216  	}
   217  }
   218  
   219  func TestGetDottedRelativePath(t *testing.T) {
   220  	// on Windows this will receive both kinds, both country and western ...
   221  	for _, f := range []func(string) string{filepath.FromSlash, func(s string) string { return s }} {
   222  		doTestGetDottedRelativePath(f, t)
   223  	}
   224  
   225  }
   226  
   227  func doTestGetDottedRelativePath(urlFixer func(string) string, t *testing.T) {
   228  	type test struct {
   229  		input, expected string
   230  	}
   231  	data := []test{
   232  		{"", "./"},
   233  		{urlFixer("/"), "./"},
   234  		{urlFixer("post"), "../"},
   235  		{urlFixer("/post"), "../"},
   236  		{urlFixer("post/"), "../"},
   237  		{urlFixer("tags/foo.html"), "../"},
   238  		{urlFixer("/tags/foo.html"), "../"},
   239  		{urlFixer("/post/"), "../"},
   240  		{urlFixer("////post/////"), "../"},
   241  		{urlFixer("/foo/bar/index.html"), "../../"},
   242  		{urlFixer("/foo/bar/foo/"), "../../../"},
   243  		{urlFixer("/foo/bar/foo"), "../../../"},
   244  		{urlFixer("foo/bar/foo/"), "../../../"},
   245  		{urlFixer("foo/bar/foo/bar"), "../../../../"},
   246  		{"404.html", "./"},
   247  		{"404.xml", "./"},
   248  		{"/404.html", "./"},
   249  	}
   250  	for i, d := range data {
   251  		output := GetDottedRelativePath(d.input)
   252  		if d.expected != output {
   253  			t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
   254  		}
   255  	}
   256  }
   257  
   258  func TestMakeTitle(t *testing.T) {
   259  	type test struct {
   260  		input, expected string
   261  	}
   262  	data := []test{
   263  		{"Make-Title", "Make Title"},
   264  		{"MakeTitle", "MakeTitle"},
   265  		{"make_title", "make_title"},
   266  	}
   267  	for i, d := range data {
   268  		output := MakeTitle(d.input)
   269  		if d.expected != output {
   270  			t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
   271  		}
   272  	}
   273  }
   274  
   275  // Replace Extension is probably poorly named, but the intent of the
   276  // function is to accept a path and return only the file name with a
   277  // new extension. It's intentionally designed to strip out the path
   278  // and only provide the name. We should probably rename the function to
   279  // be more explicit at some point.
   280  func TestReplaceExtension(t *testing.T) {
   281  	type test struct {
   282  		input, newext, expected string
   283  	}
   284  	data := []test{
   285  		// These work according to the above definition
   286  		{"/some/random/path/file.xml", "html", "file.html"},
   287  		{"/banana.html", "xml", "banana.xml"},
   288  		{"./banana.html", "xml", "banana.xml"},
   289  		{"banana/pie/index.html", "xml", "index.xml"},
   290  		{"../pies/fish/index.html", "xml", "index.xml"},
   291  		// but these all fail
   292  		{"filename-without-an-ext", "ext", "filename-without-an-ext.ext"},
   293  		{"/filename-without-an-ext", "ext", "filename-without-an-ext.ext"},
   294  		{"/directory/mydir/", "ext", ".ext"},
   295  		{"mydir/", "ext", ".ext"},
   296  	}
   297  
   298  	for i, d := range data {
   299  		output := ReplaceExtension(filepath.FromSlash(d.input), d.newext)
   300  		if d.expected != output {
   301  			t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
   302  		}
   303  	}
   304  }
   305  
   306  func TestDirExists(t *testing.T) {
   307  	type test struct {
   308  		input    string
   309  		expected bool
   310  	}
   311  
   312  	data := []test{
   313  		{".", true},
   314  		{"./", true},
   315  		{"..", true},
   316  		{"../", true},
   317  		{"./..", true},
   318  		{"./../", true},
   319  		{os.TempDir(), true},
   320  		{os.TempDir() + FilePathSeparator, true},
   321  		{"/", true},
   322  		{"/some-really-random-directory-name", false},
   323  		{"/some/really/random/directory/name", false},
   324  		{"./some-really-random-local-directory-name", false},
   325  		{"./some/really/random/local/directory/name", false},
   326  	}
   327  
   328  	for i, d := range data {
   329  		exists, _ := DirExists(filepath.FromSlash(d.input), new(afero.OsFs))
   330  		if d.expected != exists {
   331  			t.Errorf("Test %d failed. Expected %t got %t", i, d.expected, exists)
   332  		}
   333  	}
   334  }
   335  
   336  func TestIsDir(t *testing.T) {
   337  	type test struct {
   338  		input    string
   339  		expected bool
   340  	}
   341  	data := []test{
   342  		{"./", true},
   343  		{"/", true},
   344  		{"./this-directory-does-not-existi", false},
   345  		{"/this-absolute-directory/does-not-exist", false},
   346  	}
   347  
   348  	for i, d := range data {
   349  
   350  		exists, _ := IsDir(d.input, new(afero.OsFs))
   351  		if d.expected != exists {
   352  			t.Errorf("Test %d failed. Expected %t got %t", i, d.expected, exists)
   353  		}
   354  	}
   355  }
   356  
   357  func TestIsEmpty(t *testing.T) {
   358  	zeroSizedFile, _ := createZeroSizedFileInTempDir()
   359  	defer deleteFileInTempDir(zeroSizedFile)
   360  	nonZeroSizedFile, _ := createNonZeroSizedFileInTempDir()
   361  	defer deleteFileInTempDir(nonZeroSizedFile)
   362  	emptyDirectory, _ := createEmptyTempDir()
   363  	defer deleteTempDir(emptyDirectory)
   364  	nonEmptyZeroLengthFilesDirectory, _ := createTempDirWithZeroLengthFiles()
   365  	defer deleteTempDir(nonEmptyZeroLengthFilesDirectory)
   366  	nonEmptyNonZeroLengthFilesDirectory, _ := createTempDirWithNonZeroLengthFiles()
   367  	defer deleteTempDir(nonEmptyNonZeroLengthFilesDirectory)
   368  	nonExistentFile := os.TempDir() + "/this-file-does-not-exist.txt"
   369  	nonExistentDir := os.TempDir() + "/this/directory/does/not/exist/"
   370  
   371  	fileDoesNotExist := fmt.Errorf("%q path does not exist", nonExistentFile)
   372  	dirDoesNotExist := fmt.Errorf("%q path does not exist", nonExistentDir)
   373  
   374  	type test struct {
   375  		input          string
   376  		expectedResult bool
   377  		expectedErr    error
   378  	}
   379  
   380  	data := []test{
   381  		{zeroSizedFile.Name(), true, nil},
   382  		{nonZeroSizedFile.Name(), false, nil},
   383  		{emptyDirectory, true, nil},
   384  		{nonEmptyZeroLengthFilesDirectory, false, nil},
   385  		{nonEmptyNonZeroLengthFilesDirectory, false, nil},
   386  		{nonExistentFile, false, fileDoesNotExist},
   387  		{nonExistentDir, false, dirDoesNotExist},
   388  	}
   389  	for i, d := range data {
   390  		exists, err := IsEmpty(d.input, new(afero.OsFs))
   391  		if d.expectedResult != exists {
   392  			t.Errorf("Test %d failed. Expected result %t got %t", i, d.expectedResult, exists)
   393  		}
   394  		if d.expectedErr != nil {
   395  			if d.expectedErr.Error() != err.Error() {
   396  				t.Errorf("Test %d failed. Expected %q(%#v) got %q(%#v)", i, d.expectedErr, d.expectedErr, err, err)
   397  			}
   398  		} else {
   399  			if d.expectedErr != err {
   400  				t.Errorf("Test %d failed. Expected %q(%#v) got %q(%#v)", i, d.expectedErr, d.expectedErr, err, err)
   401  			}
   402  		}
   403  	}
   404  }
   405  
   406  func createZeroSizedFileInTempDir() (*os.File, error) {
   407  	filePrefix := "_path_test_"
   408  	f, e := ioutil.TempFile("", filePrefix) // dir is os.TempDir()
   409  	if e != nil {
   410  		// if there was an error no file was created.
   411  		// => no requirement to delete the file
   412  		return nil, e
   413  	}
   414  	return f, nil
   415  }
   416  
   417  func createNonZeroSizedFileInTempDir() (*os.File, error) {
   418  	f, err := createZeroSizedFileInTempDir()
   419  	if err != nil {
   420  		// no file ??
   421  	}
   422  	byteString := []byte("byteString")
   423  	err = ioutil.WriteFile(f.Name(), byteString, 0644)
   424  	if err != nil {
   425  		// delete the file
   426  		deleteFileInTempDir(f)
   427  		return nil, err
   428  	}
   429  	return f, nil
   430  }
   431  
   432  func deleteFileInTempDir(f *os.File) {
   433  	err := os.Remove(f.Name())
   434  	if err != nil {
   435  		// now what?
   436  	}
   437  }
   438  
   439  func createEmptyTempDir() (string, error) {
   440  	dirPrefix := "_dir_prefix_"
   441  	d, e := ioutil.TempDir("", dirPrefix) // will be in os.TempDir()
   442  	if e != nil {
   443  		// no directory to delete - it was never created
   444  		return "", e
   445  	}
   446  	return d, nil
   447  }
   448  
   449  func createTempDirWithZeroLengthFiles() (string, error) {
   450  	d, dirErr := createEmptyTempDir()
   451  	if dirErr != nil {
   452  		//now what?
   453  	}
   454  	filePrefix := "_path_test_"
   455  	_, fileErr := ioutil.TempFile(d, filePrefix) // dir is os.TempDir()
   456  	if fileErr != nil {
   457  		// if there was an error no file was created.
   458  		// but we need to remove the directory to clean-up
   459  		deleteTempDir(d)
   460  		return "", fileErr
   461  	}
   462  	// the dir now has one, zero length file in it
   463  	return d, nil
   464  
   465  }
   466  
   467  func createTempDirWithNonZeroLengthFiles() (string, error) {
   468  	d, dirErr := createEmptyTempDir()
   469  	if dirErr != nil {
   470  		//now what?
   471  	}
   472  	filePrefix := "_path_test_"
   473  	f, fileErr := ioutil.TempFile(d, filePrefix) // dir is os.TempDir()
   474  	if fileErr != nil {
   475  		// if there was an error no file was created.
   476  		// but we need to remove the directory to clean-up
   477  		deleteTempDir(d)
   478  		return "", fileErr
   479  	}
   480  	byteString := []byte("byteString")
   481  
   482  	fileErr = ioutil.WriteFile(f.Name(), byteString, 0644)
   483  	if fileErr != nil {
   484  		// delete the file
   485  		deleteFileInTempDir(f)
   486  		// also delete the directory
   487  		deleteTempDir(d)
   488  		return "", fileErr
   489  	}
   490  
   491  	// the dir now has one, zero length file in it
   492  	return d, nil
   493  
   494  }
   495  
   496  func deleteTempDir(d string) {
   497  	err := os.RemoveAll(d)
   498  	if err != nil {
   499  		// now what?
   500  	}
   501  }
   502  
   503  func TestExists(t *testing.T) {
   504  	zeroSizedFile, _ := createZeroSizedFileInTempDir()
   505  	defer deleteFileInTempDir(zeroSizedFile)
   506  	nonZeroSizedFile, _ := createNonZeroSizedFileInTempDir()
   507  	defer deleteFileInTempDir(nonZeroSizedFile)
   508  	emptyDirectory, _ := createEmptyTempDir()
   509  	defer deleteTempDir(emptyDirectory)
   510  	nonExistentFile := os.TempDir() + "/this-file-does-not-exist.txt"
   511  	nonExistentDir := os.TempDir() + "/this/directory/does/not/exist/"
   512  
   513  	type test struct {
   514  		input          string
   515  		expectedResult bool
   516  		expectedErr    error
   517  	}
   518  
   519  	data := []test{
   520  		{zeroSizedFile.Name(), true, nil},
   521  		{nonZeroSizedFile.Name(), true, nil},
   522  		{emptyDirectory, true, nil},
   523  		{nonExistentFile, false, nil},
   524  		{nonExistentDir, false, nil},
   525  	}
   526  	for i, d := range data {
   527  		exists, err := Exists(d.input, new(afero.OsFs))
   528  		if d.expectedResult != exists {
   529  			t.Errorf("Test %d failed. Expected result %t got %t", i, d.expectedResult, exists)
   530  		}
   531  		if d.expectedErr != err {
   532  			t.Errorf("Test %d failed. Expected %q got %q", i, d.expectedErr, err)
   533  		}
   534  	}
   535  
   536  }
   537  
   538  func TestAbsPathify(t *testing.T) {
   539  	defer viper.Reset()
   540  
   541  	type test struct {
   542  		inPath, workingDir, expected string
   543  	}
   544  	data := []test{
   545  		{os.TempDir(), filepath.FromSlash("/work"), filepath.Clean(os.TempDir())}, // TempDir has trailing slash
   546  		{"dir", filepath.FromSlash("/work"), filepath.FromSlash("/work/dir")},
   547  	}
   548  
   549  	windowsData := []test{
   550  		{"c:\\banana\\..\\dir", "c:\\foo", "c:\\dir"},
   551  		{"\\dir", "c:\\foo", "c:\\foo\\dir"},
   552  		{"c:\\", "c:\\foo", "c:\\"},
   553  	}
   554  
   555  	unixData := []test{
   556  		{"/banana/../dir/", "/work", "/dir"},
   557  	}
   558  
   559  	for i, d := range data {
   560  		viper.Reset()
   561  		// todo see comment in AbsPathify
   562  		ps := newTestDefaultPathSpec("workingDir", d.workingDir)
   563  
   564  		expected := ps.AbsPathify(d.inPath)
   565  		if d.expected != expected {
   566  			t.Errorf("Test %d failed. Expected %q but got %q", i, d.expected, expected)
   567  		}
   568  	}
   569  	t.Logf("Running platform specific path tests for %s", runtime.GOOS)
   570  	if runtime.GOOS == "windows" {
   571  		for i, d := range windowsData {
   572  			ps := newTestDefaultPathSpec("workingDir", d.workingDir)
   573  
   574  			expected := ps.AbsPathify(d.inPath)
   575  			if d.expected != expected {
   576  				t.Errorf("Test %d failed. Expected %q but got %q", i, d.expected, expected)
   577  			}
   578  		}
   579  	} else {
   580  		for i, d := range unixData {
   581  			ps := newTestDefaultPathSpec("workingDir", d.workingDir)
   582  
   583  			expected := ps.AbsPathify(d.inPath)
   584  			if d.expected != expected {
   585  				t.Errorf("Test %d failed. Expected %q but got %q", i, d.expected, expected)
   586  			}
   587  		}
   588  	}
   589  
   590  }
   591  
   592  func TestExtNoDelimiter(t *testing.T) {
   593  	assert := require.New(t)
   594  	assert.Equal("json", ExtNoDelimiter(filepath.FromSlash("/my/data.json")))
   595  }
   596  
   597  func TestFilename(t *testing.T) {
   598  	type test struct {
   599  		input, expected string
   600  	}
   601  	data := []test{
   602  		{"index.html", "index"},
   603  		{"./index.html", "index"},
   604  		{"/index.html", "index"},
   605  		{"index", "index"},
   606  		{"/tmp/index.html", "index"},
   607  		{"./filename-no-ext", "filename-no-ext"},
   608  		{"/filename-no-ext", "filename-no-ext"},
   609  		{"filename-no-ext", "filename-no-ext"},
   610  		{"directory/", ""}, // no filename case??
   611  		{"directory/.hidden.ext", ".hidden"},
   612  		{"./directory/../~/banana/gold.fish", "gold"},
   613  		{"../directory/banana.man", "banana"},
   614  		{"~/mydir/filename.ext", "filename"},
   615  		{"./directory//tmp/filename.ext", "filename"},
   616  	}
   617  
   618  	for i, d := range data {
   619  		output := Filename(filepath.FromSlash(d.input))
   620  		if d.expected != output {
   621  			t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
   622  		}
   623  	}
   624  }
   625  
   626  func TestFileAndExt(t *testing.T) {
   627  	type test struct {
   628  		input, expectedFile, expectedExt string
   629  	}
   630  	data := []test{
   631  		{"index.html", "index", ".html"},
   632  		{"./index.html", "index", ".html"},
   633  		{"/index.html", "index", ".html"},
   634  		{"index", "index", ""},
   635  		{"/tmp/index.html", "index", ".html"},
   636  		{"./filename-no-ext", "filename-no-ext", ""},
   637  		{"/filename-no-ext", "filename-no-ext", ""},
   638  		{"filename-no-ext", "filename-no-ext", ""},
   639  		{"directory/", "", ""}, // no filename case??
   640  		{"directory/.hidden.ext", ".hidden", ".ext"},
   641  		{"./directory/../~/banana/gold.fish", "gold", ".fish"},
   642  		{"../directory/banana.man", "banana", ".man"},
   643  		{"~/mydir/filename.ext", "filename", ".ext"},
   644  		{"./directory//tmp/filename.ext", "filename", ".ext"},
   645  	}
   646  
   647  	for i, d := range data {
   648  		file, ext := fileAndExt(filepath.FromSlash(d.input), fpb)
   649  		if d.expectedFile != file {
   650  			t.Errorf("Test %d failed. Expected filename %q got %q.", i, d.expectedFile, file)
   651  		}
   652  		if d.expectedExt != ext {
   653  			t.Errorf("Test %d failed. Expected extension %q got %q.", i, d.expectedExt, ext)
   654  		}
   655  	}
   656  
   657  }
   658  
   659  func TestPathPrep(t *testing.T) {
   660  
   661  }
   662  
   663  func TestPrettifyPath(t *testing.T) {
   664  
   665  }
   666  
   667  func TestExtractRootPaths(t *testing.T) {
   668  	tests := []struct {
   669  		input    []string
   670  		expected []string
   671  	}{{[]string{filepath.FromSlash("a/b"), filepath.FromSlash("a/b/c/"), "b",
   672  		filepath.FromSlash("/c/d"), filepath.FromSlash("d/"), filepath.FromSlash("//e//")},
   673  		[]string{"a", "a", "b", "c", "d", "e"}}}
   674  
   675  	for _, test := range tests {
   676  		output := ExtractRootPaths(test.input)
   677  		if !reflect.DeepEqual(output, test.expected) {
   678  			t.Errorf("Expected %#v, got %#v\n", test.expected, output)
   679  		}
   680  	}
   681  }
   682  
   683  func TestFindCWD(t *testing.T) {
   684  	type test struct {
   685  		expectedDir string
   686  		expectedErr error
   687  	}
   688  
   689  	//cwd, _ := os.Getwd()
   690  	data := []test{
   691  		//{cwd, nil},
   692  		// Commenting this out. It doesn't work properly.
   693  		// There's a good reason why we don't use os.Getwd(), it doesn't actually work the way we want it to.
   694  		// I really don't know a better way to test this function. - SPF 2014.11.04
   695  	}
   696  	for i, d := range data {
   697  		dir, err := FindCWD()
   698  		if d.expectedDir != dir {
   699  			t.Errorf("Test %d failed. Expected %q but got %q", i, d.expectedDir, dir)
   700  		}
   701  		if d.expectedErr != err {
   702  			t.Errorf("Test %d failed. Expected %q but got %q", i, d.expectedErr, err)
   703  		}
   704  	}
   705  }
   706  
   707  func TestSafeWriteToDisk(t *testing.T) {
   708  	emptyFile, _ := createZeroSizedFileInTempDir()
   709  	defer deleteFileInTempDir(emptyFile)
   710  	tmpDir, _ := createEmptyTempDir()
   711  	defer deleteTempDir(tmpDir)
   712  
   713  	randomString := "This is a random string!"
   714  	reader := strings.NewReader(randomString)
   715  
   716  	fileExists := fmt.Errorf("%v already exists", emptyFile.Name())
   717  
   718  	type test struct {
   719  		filename    string
   720  		expectedErr error
   721  	}
   722  
   723  	now := time.Now().Unix()
   724  	nowStr := strconv.FormatInt(now, 10)
   725  	data := []test{
   726  		{emptyFile.Name(), fileExists},
   727  		{tmpDir + "/" + nowStr, nil},
   728  	}
   729  
   730  	for i, d := range data {
   731  		e := SafeWriteToDisk(d.filename, reader, new(afero.OsFs))
   732  		if d.expectedErr != nil {
   733  			if d.expectedErr.Error() != e.Error() {
   734  				t.Errorf("Test %d failed. Expected error %q but got %q", i, d.expectedErr.Error(), e.Error())
   735  			}
   736  		} else {
   737  			if d.expectedErr != e {
   738  				t.Errorf("Test %d failed. Expected %q but got %q", i, d.expectedErr, e)
   739  			}
   740  			contents, _ := ioutil.ReadFile(d.filename)
   741  			if randomString != string(contents) {
   742  				t.Errorf("Test %d failed. Expected contents %q but got %q", i, randomString, string(contents))
   743  			}
   744  		}
   745  		reader.Seek(0, 0)
   746  	}
   747  }
   748  
   749  func TestWriteToDisk(t *testing.T) {
   750  	emptyFile, _ := createZeroSizedFileInTempDir()
   751  	defer deleteFileInTempDir(emptyFile)
   752  	tmpDir, _ := createEmptyTempDir()
   753  	defer deleteTempDir(tmpDir)
   754  
   755  	randomString := "This is a random string!"
   756  	reader := strings.NewReader(randomString)
   757  
   758  	type test struct {
   759  		filename    string
   760  		expectedErr error
   761  	}
   762  
   763  	now := time.Now().Unix()
   764  	nowStr := strconv.FormatInt(now, 10)
   765  	data := []test{
   766  		{emptyFile.Name(), nil},
   767  		{tmpDir + "/" + nowStr, nil},
   768  	}
   769  
   770  	for i, d := range data {
   771  		e := WriteToDisk(d.filename, reader, new(afero.OsFs))
   772  		if d.expectedErr != e {
   773  			t.Errorf("Test %d failed. WriteToDisk Error Expected %q but got %q", i, d.expectedErr, e)
   774  		}
   775  		contents, e := ioutil.ReadFile(d.filename)
   776  		if e != nil {
   777  			t.Errorf("Test %d failed. Could not read file %s. Reason: %s\n", i, d.filename, e)
   778  		}
   779  		if randomString != string(contents) {
   780  			t.Errorf("Test %d failed. Expected contents %q but got %q", i, randomString, string(contents))
   781  		}
   782  		reader.Seek(0, 0)
   783  	}
   784  }
   785  
   786  func TestGetTempDir(t *testing.T) {
   787  	dir := os.TempDir()
   788  	if FilePathSeparator != dir[len(dir)-1:] {
   789  		dir = dir + FilePathSeparator
   790  	}
   791  	testDir := "hugoTestFolder" + FilePathSeparator
   792  	tests := []struct {
   793  		input    string
   794  		expected string
   795  	}{
   796  		{"", dir},
   797  		{testDir + "  Foo bar  ", dir + testDir + "  Foo bar  " + FilePathSeparator},
   798  		{testDir + "Foo.Bar/foo_Bar-Foo", dir + testDir + "Foo.Bar/foo_Bar-Foo" + FilePathSeparator},
   799  		{testDir + "fOO,bar:foo%bAR", dir + testDir + "fOObarfoo%bAR" + FilePathSeparator},
   800  		{testDir + "fOO,bar:foobAR", dir + testDir + "fOObarfoobAR" + FilePathSeparator},
   801  		{testDir + "FOo/BaR.html", dir + testDir + "FOo/BaR.html" + FilePathSeparator},
   802  		{testDir + "трям/трям", dir + testDir + "трям/трям" + FilePathSeparator},
   803  		{testDir + "은행", dir + testDir + "은행" + FilePathSeparator},
   804  		{testDir + "Банковский кассир", dir + testDir + "Банковский кассир" + FilePathSeparator},
   805  	}
   806  
   807  	for _, test := range tests {
   808  		output := GetTempDir(test.input, new(afero.MemMapFs))
   809  		if output != test.expected {
   810  			t.Errorf("Expected %#v, got %#v\n", test.expected, output)
   811  		}
   812  	}
   813  }