github.com/pietrocarrara/hugo@v0.47.1/hugolib/filesystems/basefs_test.go (about)

     1  // Copyright 2018 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 filesystems
    15  
    16  import (
    17  	"errors"
    18  	"fmt"
    19  	"os"
    20  	"path/filepath"
    21  	"testing"
    22  
    23  	"github.com/gohugoio/hugo/langs"
    24  
    25  	"github.com/spf13/afero"
    26  
    27  	"github.com/gohugoio/hugo/hugofs"
    28  	"github.com/gohugoio/hugo/hugolib/paths"
    29  	"github.com/spf13/viper"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  func TestNewBaseFs(t *testing.T) {
    34  	assert := require.New(t)
    35  	v := viper.New()
    36  
    37  	fs := hugofs.NewMem(v)
    38  
    39  	themes := []string{"btheme", "atheme"}
    40  
    41  	workingDir := filepath.FromSlash("/my/work")
    42  	v.Set("workingDir", workingDir)
    43  	v.Set("themesDir", "themes")
    44  	v.Set("theme", themes[:1])
    45  
    46  	// Write some data to the themes
    47  	for _, theme := range themes {
    48  		for _, dir := range []string{"i18n", "data"} {
    49  			base := filepath.Join(workingDir, "themes", theme, dir)
    50  			fs.Source.Mkdir(base, 0755)
    51  			afero.WriteFile(fs.Source, filepath.Join(base, fmt.Sprintf("theme-file-%s-%s.txt", theme, dir)), []byte(fmt.Sprintf("content:%s:%s", theme, dir)), 0755)
    52  		}
    53  		// Write some files to the root of the theme
    54  		base := filepath.Join(workingDir, "themes", theme)
    55  		afero.WriteFile(fs.Source, filepath.Join(base, fmt.Sprintf("theme-root-%s.txt", theme)), []byte(fmt.Sprintf("content:%s", theme)), 0755)
    56  		afero.WriteFile(fs.Source, filepath.Join(base, "file-root.txt"), []byte(fmt.Sprintf("content:%s", theme)), 0755)
    57  	}
    58  
    59  	afero.WriteFile(fs.Source, filepath.Join(workingDir, "file-root.txt"), []byte("content-project"), 0755)
    60  
    61  	afero.WriteFile(fs.Source, filepath.Join(workingDir, "themes", "btheme", "config.toml"), []byte(`
    62  theme = ["atheme"]
    63  `), 0755)
    64  
    65  	setConfigAndWriteSomeFilesTo(fs.Source, v, "contentDir", "mycontent", 3)
    66  	setConfigAndWriteSomeFilesTo(fs.Source, v, "i18nDir", "myi18n", 4)
    67  	setConfigAndWriteSomeFilesTo(fs.Source, v, "layoutDir", "mylayouts", 5)
    68  	setConfigAndWriteSomeFilesTo(fs.Source, v, "staticDir", "mystatic", 6)
    69  	setConfigAndWriteSomeFilesTo(fs.Source, v, "dataDir", "mydata", 7)
    70  	setConfigAndWriteSomeFilesTo(fs.Source, v, "archetypeDir", "myarchetypes", 8)
    71  	setConfigAndWriteSomeFilesTo(fs.Source, v, "assetDir", "myassets", 9)
    72  	setConfigAndWriteSomeFilesTo(fs.Source, v, "resourceDir", "myrsesource", 10)
    73  
    74  	v.Set("publishDir", "public")
    75  
    76  	p, err := paths.New(fs, v)
    77  	assert.NoError(err)
    78  
    79  	bfs, err := NewBase(p)
    80  	assert.NoError(err)
    81  	assert.NotNil(bfs)
    82  
    83  	root, err := bfs.I18n.Fs.Open("")
    84  	assert.NoError(err)
    85  	dirnames, err := root.Readdirnames(-1)
    86  	assert.NoError(err)
    87  	assert.Equal([]string{projectVirtualFolder, "btheme", "atheme"}, dirnames)
    88  	ff, err := bfs.I18n.Fs.Open("myi18n")
    89  	assert.NoError(err)
    90  	_, err = ff.Readdirnames(-1)
    91  	assert.NoError(err)
    92  
    93  	root, err = bfs.Data.Fs.Open("")
    94  	assert.NoError(err)
    95  	dirnames, err = root.Readdirnames(-1)
    96  	assert.NoError(err)
    97  	assert.Equal([]string{projectVirtualFolder, "btheme", "atheme"}, dirnames)
    98  	ff, err = bfs.I18n.Fs.Open("mydata")
    99  	assert.NoError(err)
   100  	_, err = ff.Readdirnames(-1)
   101  	assert.NoError(err)
   102  
   103  	checkFileCount(bfs.Content.Fs, "", assert, 3)
   104  	checkFileCount(bfs.I18n.Fs, "", assert, 6) // 4 + 2 themes
   105  	checkFileCount(bfs.Layouts.Fs, "", assert, 5)
   106  	checkFileCount(bfs.Static[""].Fs, "", assert, 6)
   107  	checkFileCount(bfs.Data.Fs, "", assert, 9) // 7 + 2 themes
   108  	checkFileCount(bfs.Archetypes.Fs, "", assert, 8)
   109  	checkFileCount(bfs.Assets.Fs, "", assert, 9)
   110  	checkFileCount(bfs.Resources.Fs, "", assert, 10)
   111  	checkFileCount(bfs.Work.Fs, "", assert, 69)
   112  
   113  	assert.Equal([]string{filepath.FromSlash("/my/work/mydata"), filepath.FromSlash("/my/work/themes/btheme/data"), filepath.FromSlash("/my/work/themes/atheme/data")}, bfs.Data.Dirnames)
   114  
   115  	assert.True(bfs.IsData(filepath.Join(workingDir, "mydata", "file1.txt")))
   116  	assert.True(bfs.IsI18n(filepath.Join(workingDir, "myi18n", "file1.txt")))
   117  	assert.True(bfs.IsLayout(filepath.Join(workingDir, "mylayouts", "file1.txt")))
   118  	assert.True(bfs.IsStatic(filepath.Join(workingDir, "mystatic", "file1.txt")))
   119  	assert.True(bfs.IsAsset(filepath.Join(workingDir, "myassets", "file1.txt")))
   120  
   121  	contentFilename := filepath.Join(workingDir, "mycontent", "file1.txt")
   122  	assert.True(bfs.IsContent(contentFilename))
   123  	rel := bfs.RelContentDir(contentFilename)
   124  	assert.Equal("file1.txt", rel)
   125  
   126  	// Check Work fs vs theme
   127  	checkFileContent(bfs.Work.Fs, "file-root.txt", assert, "content-project")
   128  	checkFileContent(bfs.Work.Fs, "theme-root-atheme.txt", assert, "content:atheme")
   129  
   130  }
   131  
   132  func createConfig() *viper.Viper {
   133  	v := viper.New()
   134  	v.Set("contentDir", "mycontent")
   135  	v.Set("i18nDir", "myi18n")
   136  	v.Set("staticDir", "mystatic")
   137  	v.Set("dataDir", "mydata")
   138  	v.Set("layoutDir", "mylayouts")
   139  	v.Set("archetypeDir", "myarchetypes")
   140  	v.Set("assetDir", "myassets")
   141  	v.Set("resourceDir", "resources")
   142  	v.Set("publishDir", "public")
   143  
   144  	return v
   145  }
   146  
   147  func TestNewBaseFsEmpty(t *testing.T) {
   148  	assert := require.New(t)
   149  	v := createConfig()
   150  	fs := hugofs.NewMem(v)
   151  	p, err := paths.New(fs, v)
   152  	assert.NoError(err)
   153  	bfs, err := NewBase(p)
   154  	assert.NoError(err)
   155  	assert.NotNil(bfs)
   156  	assert.Equal(hugofs.NoOpFs, bfs.Archetypes.Fs)
   157  	assert.Equal(hugofs.NoOpFs, bfs.Layouts.Fs)
   158  	assert.Equal(hugofs.NoOpFs, bfs.Data.Fs)
   159  	assert.Equal(hugofs.NoOpFs, bfs.Assets.Fs)
   160  	assert.Equal(hugofs.NoOpFs, bfs.I18n.Fs)
   161  	assert.NotNil(bfs.Work.Fs)
   162  	assert.NotNil(bfs.Content.Fs)
   163  	assert.NotNil(bfs.Static)
   164  }
   165  
   166  func TestRealDirs(t *testing.T) {
   167  	assert := require.New(t)
   168  	v := createConfig()
   169  	fs := hugofs.NewDefault(v)
   170  	sfs := fs.Source
   171  
   172  	root, err := afero.TempDir(sfs, "", "realdir")
   173  	assert.NoError(err)
   174  	themesDir, err := afero.TempDir(sfs, "", "themesDir")
   175  	assert.NoError(err)
   176  	defer func() {
   177  		os.RemoveAll(root)
   178  		os.RemoveAll(themesDir)
   179  	}()
   180  
   181  	v.Set("workingDir", root)
   182  	v.Set("themesDir", themesDir)
   183  	v.Set("theme", "mytheme")
   184  
   185  	assert.NoError(sfs.MkdirAll(filepath.Join(root, "myassets", "scss", "sf1"), 0755))
   186  	assert.NoError(sfs.MkdirAll(filepath.Join(root, "myassets", "scss", "sf2"), 0755))
   187  	assert.NoError(sfs.MkdirAll(filepath.Join(themesDir, "mytheme", "assets", "scss", "sf2"), 0755))
   188  	assert.NoError(sfs.MkdirAll(filepath.Join(themesDir, "mytheme", "assets", "scss", "sf3"), 0755))
   189  	assert.NoError(sfs.MkdirAll(filepath.Join(root, "resources"), 0755))
   190  	assert.NoError(sfs.MkdirAll(filepath.Join(themesDir, "mytheme", "resources"), 0755))
   191  
   192  	assert.NoError(sfs.MkdirAll(filepath.Join(root, "myassets", "js", "f2"), 0755))
   193  
   194  	afero.WriteFile(sfs, filepath.Join(filepath.Join(root, "myassets", "scss", "sf1", "a1.scss")), []byte("content"), 0755)
   195  	afero.WriteFile(sfs, filepath.Join(filepath.Join(root, "myassets", "scss", "sf2", "a3.scss")), []byte("content"), 0755)
   196  	afero.WriteFile(sfs, filepath.Join(filepath.Join(root, "myassets", "scss", "a2.scss")), []byte("content"), 0755)
   197  	afero.WriteFile(sfs, filepath.Join(filepath.Join(themesDir, "mytheme", "assets", "scss", "sf2", "a3.scss")), []byte("content"), 0755)
   198  	afero.WriteFile(sfs, filepath.Join(filepath.Join(themesDir, "mytheme", "assets", "scss", "sf3", "a4.scss")), []byte("content"), 0755)
   199  
   200  	afero.WriteFile(sfs, filepath.Join(filepath.Join(themesDir, "mytheme", "resources", "t1.txt")), []byte("content"), 0755)
   201  	afero.WriteFile(sfs, filepath.Join(filepath.Join(root, "resources", "p1.txt")), []byte("content"), 0755)
   202  	afero.WriteFile(sfs, filepath.Join(filepath.Join(root, "resources", "p2.txt")), []byte("content"), 0755)
   203  
   204  	afero.WriteFile(sfs, filepath.Join(filepath.Join(root, "myassets", "js", "f2", "a1.js")), []byte("content"), 0755)
   205  	afero.WriteFile(sfs, filepath.Join(filepath.Join(root, "myassets", "js", "a2.js")), []byte("content"), 0755)
   206  
   207  	p, err := paths.New(fs, v)
   208  	assert.NoError(err)
   209  	bfs, err := NewBase(p)
   210  	assert.NoError(err)
   211  	assert.NotNil(bfs)
   212  	checkFileCount(bfs.Assets.Fs, "", assert, 6)
   213  
   214  	realDirs := bfs.Assets.RealDirs("scss")
   215  	assert.Equal(2, len(realDirs))
   216  	assert.Equal(filepath.Join(root, "myassets/scss"), realDirs[0])
   217  	assert.Equal(filepath.Join(themesDir, "mytheme/assets/scss"), realDirs[len(realDirs)-1])
   218  
   219  	checkFileCount(bfs.Resources.Fs, "", assert, 3)
   220  
   221  }
   222  
   223  func TestStaticFs(t *testing.T) {
   224  	assert := require.New(t)
   225  	v := createConfig()
   226  	workDir := "mywork"
   227  	v.Set("workingDir", workDir)
   228  	v.Set("themesDir", "themes")
   229  	v.Set("theme", "t1")
   230  
   231  	fs := hugofs.NewMem(v)
   232  
   233  	themeStaticDir := filepath.Join(workDir, "themes", "t1", "static")
   234  
   235  	afero.WriteFile(fs.Source, filepath.Join(workDir, "mystatic", "f1.txt"), []byte("Hugo Rocks!"), 0755)
   236  	afero.WriteFile(fs.Source, filepath.Join(themeStaticDir, "f1.txt"), []byte("Hugo Themes Rocks!"), 0755)
   237  	afero.WriteFile(fs.Source, filepath.Join(themeStaticDir, "f2.txt"), []byte("Hugo Themes Still Rocks!"), 0755)
   238  
   239  	p, err := paths.New(fs, v)
   240  	assert.NoError(err)
   241  	bfs, err := NewBase(p)
   242  	sfs := bfs.StaticFs("en")
   243  	checkFileContent(sfs, "f1.txt", assert, "Hugo Rocks!")
   244  	checkFileContent(sfs, "f2.txt", assert, "Hugo Themes Still Rocks!")
   245  
   246  }
   247  
   248  func TestStaticFsMultiHost(t *testing.T) {
   249  	assert := require.New(t)
   250  	v := createConfig()
   251  	workDir := "mywork"
   252  	v.Set("workingDir", workDir)
   253  	v.Set("themesDir", "themes")
   254  	v.Set("theme", "t1")
   255  	v.Set("multihost", true)
   256  
   257  	vn := viper.New()
   258  	vn.Set("staticDir", "nn_static")
   259  
   260  	en := langs.NewLanguage("en", v)
   261  	no := langs.NewLanguage("no", v)
   262  	no.Set("staticDir", "static_no")
   263  
   264  	languages := langs.Languages{
   265  		en,
   266  		no,
   267  	}
   268  
   269  	v.Set("languagesSorted", languages)
   270  
   271  	fs := hugofs.NewMem(v)
   272  
   273  	themeStaticDir := filepath.Join(workDir, "themes", "t1", "static")
   274  
   275  	afero.WriteFile(fs.Source, filepath.Join(workDir, "mystatic", "f1.txt"), []byte("Hugo Rocks!"), 0755)
   276  	afero.WriteFile(fs.Source, filepath.Join(workDir, "static_no", "f1.txt"), []byte("Hugo Rocks in Norway!"), 0755)
   277  
   278  	afero.WriteFile(fs.Source, filepath.Join(themeStaticDir, "f1.txt"), []byte("Hugo Themes Rocks!"), 0755)
   279  	afero.WriteFile(fs.Source, filepath.Join(themeStaticDir, "f2.txt"), []byte("Hugo Themes Still Rocks!"), 0755)
   280  
   281  	p, err := paths.New(fs, v)
   282  	assert.NoError(err)
   283  	bfs, err := NewBase(p)
   284  	enFs := bfs.StaticFs("en")
   285  	checkFileContent(enFs, "f1.txt", assert, "Hugo Rocks!")
   286  	checkFileContent(enFs, "f2.txt", assert, "Hugo Themes Still Rocks!")
   287  
   288  	noFs := bfs.StaticFs("no")
   289  	checkFileContent(noFs, "f1.txt", assert, "Hugo Rocks in Norway!")
   290  	checkFileContent(noFs, "f2.txt", assert, "Hugo Themes Still Rocks!")
   291  }
   292  
   293  func checkFileCount(fs afero.Fs, dirname string, assert *require.Assertions, expected int) {
   294  	count, _, err := countFileaAndGetDirs(fs, dirname)
   295  	assert.NoError(err)
   296  	assert.Equal(expected, count)
   297  }
   298  
   299  func checkFileContent(fs afero.Fs, filename string, assert *require.Assertions, expected ...string) {
   300  
   301  	b, err := afero.ReadFile(fs, filename)
   302  	assert.NoError(err)
   303  
   304  	content := string(b)
   305  
   306  	for _, e := range expected {
   307  		assert.Contains(content, e)
   308  	}
   309  }
   310  
   311  func countFileaAndGetDirs(fs afero.Fs, dirname string) (int, []string, error) {
   312  	if fs == nil {
   313  		return 0, nil, errors.New("no fs")
   314  	}
   315  
   316  	counter := 0
   317  	var dirs []string
   318  
   319  	afero.Walk(fs, dirname, func(path string, info os.FileInfo, err error) error {
   320  		if info != nil {
   321  			if !info.IsDir() {
   322  				counter++
   323  			} else if info.Name() != "." {
   324  				dirs = append(dirs, filepath.Join(path, info.Name()))
   325  			}
   326  		}
   327  
   328  		return nil
   329  	})
   330  
   331  	return counter, dirs, nil
   332  }
   333  
   334  func setConfigAndWriteSomeFilesTo(fs afero.Fs, v *viper.Viper, key, val string, num int) {
   335  	workingDir := v.GetString("workingDir")
   336  	v.Set(key, val)
   337  	fs.Mkdir(val, 0755)
   338  	for i := 0; i < num; i++ {
   339  		afero.WriteFile(fs, filepath.Join(workingDir, val, fmt.Sprintf("file%d.txt", i+1)), []byte(fmt.Sprintf("content:%s:%d", key, i+1)), 0755)
   340  	}
   341  }