2017-01-10 04:55:03 -05:00
package hugolib
import (
"path/filepath"
"testing"
2017-02-17 14:52:50 -05:00
"regexp"
"fmt"
"strings"
2017-02-20 03:33:35 -05:00
"github.com/spf13/afero"
"github.com/spf13/hugo/config"
"github.com/spf13/hugo/deps"
2017-01-10 04:55:03 -05:00
"github.com/spf13/hugo/helpers"
"github.com/spf13/hugo/source"
2017-02-17 07:30:50 -05:00
"github.com/spf13/hugo/tpl"
2017-01-10 04:55:03 -05:00
"github.com/spf13/viper"
2017-02-04 22:20:06 -05:00
"io/ioutil"
"os"
"log"
"github.com/spf13/hugo/hugofs"
jww "github.com/spf13/jwalterweatherman"
2017-01-10 04:55:03 -05:00
"github.com/stretchr/testify/require"
)
2017-02-17 14:52:50 -05:00
type testHelper struct {
Cfg config . Provider
Fs * hugofs . Fs
T testing . TB
}
2017-02-17 15:14:52 -05:00
func ( th testHelper ) assertFileContent ( filename string , matches ... string ) {
filename = th . replaceDefaultContentLanguageValue ( filename )
2017-02-17 14:52:50 -05:00
content := readDestination ( th . T , th . Fs , filename )
for _ , match := range matches {
2017-02-17 15:14:52 -05:00
match = th . replaceDefaultContentLanguageValue ( match )
2017-02-17 14:52:50 -05:00
require . True ( th . T , strings . Contains ( content , match ) , fmt . Sprintf ( "File no match for\n%q in\n%q:\n%s" , strings . Replace ( match , "%" , "%%" , - 1 ) , filename , strings . Replace ( content , "%" , "%%" , - 1 ) ) )
}
}
2017-02-17 15:14:52 -05:00
// TODO(bep) better name for this. It does no magic replacements depending on defaultontentLanguageInSubDir.
func ( th testHelper ) assertFileContentStraight ( filename string , matches ... string ) {
2017-02-17 14:52:50 -05:00
content := readDestination ( th . T , th . Fs , filename )
for _ , match := range matches {
2017-02-17 15:14:52 -05:00
require . True ( th . T , strings . Contains ( content , match ) , fmt . Sprintf ( "File no match for\n%q in\n%q:\n%s" , strings . Replace ( match , "%" , "%%" , - 1 ) , filename , strings . Replace ( content , "%" , "%%" , - 1 ) ) )
}
}
func ( th testHelper ) assertFileContentRegexp ( filename string , matches ... string ) {
filename = th . replaceDefaultContentLanguageValue ( filename )
content := readDestination ( th . T , th . Fs , filename )
for _ , match := range matches {
match = th . replaceDefaultContentLanguageValue ( match )
2017-02-17 14:52:50 -05:00
r := regexp . MustCompile ( match )
require . True ( th . T , r . MatchString ( content ) , fmt . Sprintf ( "File no match for\n%q in\n%q:\n%s" , strings . Replace ( match , "%" , "%%" , - 1 ) , filename , strings . Replace ( content , "%" , "%%" , - 1 ) ) )
}
}
2017-02-17 15:14:52 -05:00
func ( th testHelper ) replaceDefaultContentLanguageValue ( value string ) string {
defaultInSubDir := th . Cfg . GetBool ( "defaultContentLanguageInSubDir" )
replace := th . Cfg . GetString ( "defaultContentLanguage" ) + "/"
if ! defaultInSubDir {
value = strings . Replace ( value , replace , "" , 1 )
}
return value
}
2017-02-04 22:20:06 -05:00
func newTestPathSpec ( fs * hugofs . Fs , v * viper . Viper ) * helpers . PathSpec {
l := helpers . NewDefaultLanguage ( v )
2017-03-25 09:37:04 -04:00
ps , _ := helpers . NewPathSpec ( fs , l )
return ps
2017-01-10 04:55:03 -05:00
}
2017-03-09 13:19:29 -05:00
func newTestDefaultPathSpec ( ) * helpers . PathSpec {
v := viper . New ( )
// Easier to reason about in tests.
v . Set ( "disablePathToLower" , true )
fs := hugofs . NewDefault ( v )
2017-03-25 09:37:04 -04:00
ps , _ := helpers . NewPathSpec ( fs , v )
return ps
2017-03-09 13:19:29 -05:00
}
2017-02-04 22:20:06 -05:00
func newTestCfg ( ) ( * viper . Viper , * hugofs . Fs ) {
v := viper . New ( )
fs := hugofs . NewMem ( v )
v . SetFs ( fs . Source )
loadDefaultSettingsFor ( v )
// Default is false, but true is easier to use as default in tests
v . Set ( "defaultContentLanguageInSubdir" , true )
return v , fs
}
// newTestSite creates a new site in the English language with in-memory Fs.
// The site will have a template system loaded and ready to use.
// Note: This is only used in single site tests.
func newTestSite ( t testing . TB , configKeyValues ... interface { } ) * Site {
cfg , fs := newTestCfg ( )
for i := 0 ; i < len ( configKeyValues ) ; i += 2 {
cfg . Set ( configKeyValues [ i ] . ( string ) , configKeyValues [ i + 1 ] )
}
2017-03-06 13:54:46 -05:00
d := deps . DepsCfg { Language : helpers . NewLanguage ( "en" , cfg ) , Fs : fs , Cfg : cfg }
2017-02-04 22:20:06 -05:00
s , err := NewSiteForCfg ( d )
if err != nil {
t . Fatalf ( "Failed to create Site: %s" , err )
}
return s
}
2017-03-27 14:43:49 -04:00
func newTestSitesFromConfig ( t testing . TB , afs afero . Fs , tomlConfig string , layoutPathContentPairs ... string ) ( testHelper , * HugoSites ) {
2017-02-20 03:33:35 -05:00
if len ( layoutPathContentPairs ) % 2 != 0 {
t . Fatalf ( "Layouts must be provided in pairs" )
}
2017-03-27 14:43:49 -04:00
writeToFs ( t , afs , "config.toml" , tomlConfig )
2017-02-20 03:33:35 -05:00
2017-03-27 14:43:49 -04:00
cfg , err := LoadConfig ( afs , "" , "config.toml" )
2017-02-20 03:33:35 -05:00
require . NoError ( t , err )
2017-03-27 14:43:49 -04:00
fs := hugofs . NewFrom ( afs , cfg )
2017-02-20 03:33:35 -05:00
th := testHelper { cfg , fs , t }
for i := 0 ; i < len ( layoutPathContentPairs ) ; i += 2 {
writeSource ( t , fs , layoutPathContentPairs [ i ] , layoutPathContentPairs [ i + 1 ] )
}
h , err := NewHugoSites ( deps . DepsCfg { Fs : fs , Cfg : cfg } )
require . NoError ( t , err )
return th , h
}
func newTestSitesFromConfigWithDefaultTemplates ( t testing . TB , tomlConfig string ) ( testHelper , * HugoSites ) {
2017-03-27 14:43:49 -04:00
return newTestSitesFromConfig ( t , afero . NewMemMapFs ( ) , tomlConfig ,
2017-02-20 03:33:35 -05:00
"layouts/_default/single.html" , "Single|{{ .Title }}|{{ .Content }}" ,
"layouts/_default/list.html" , "List|{{ .Title }}|{{ .Content }}" ,
"layouts/_default/terms.html" , "Terms List|{{ .Title }}|{{ .Content }}" ,
)
}
2017-02-04 22:20:06 -05:00
func newDebugLogger ( ) * jww . Notepad {
return jww . NewNotepad ( jww . LevelDebug , jww . LevelError , os . Stdout , ioutil . Discard , "" , log . Ldate | log . Ltime )
2017-01-10 04:55:03 -05:00
}
2017-03-03 04:47:43 -05:00
func newErrorLogger ( ) * jww . Notepad {
return jww . NewNotepad ( jww . LevelError , jww . LevelError , os . Stdout , ioutil . Discard , "" , log . Ldate | log . Ltime )
}
2017-03-27 14:43:49 -04:00
func createWithTemplateFromNameValues ( additionalTemplates ... string ) func ( templ tpl . TemplateHandler ) error {
2017-01-10 04:55:03 -05:00
2017-03-27 14:43:49 -04:00
return func ( templ tpl . TemplateHandler ) error {
2017-01-10 04:55:03 -05:00
for i := 0 ; i < len ( additionalTemplates ) ; i += 2 {
err := templ . AddTemplate ( additionalTemplates [ i ] , additionalTemplates [ i + 1 ] )
if err != nil {
return err
}
}
return nil
}
}
func buildSingleSite ( t * testing . T , depsCfg deps . DepsCfg , buildCfg BuildCfg ) * Site {
2017-02-04 22:20:06 -05:00
return buildSingleSiteExpected ( t , false , depsCfg , buildCfg )
}
func buildSingleSiteExpected ( t * testing . T , expectBuildError bool , depsCfg deps . DepsCfg , buildCfg BuildCfg ) * Site {
h , err := NewHugoSites ( depsCfg )
2017-01-10 04:55:03 -05:00
require . NoError ( t , err )
require . Len ( t , h . Sites , 1 )
2017-02-04 22:20:06 -05:00
if expectBuildError {
require . Error ( t , h . Build ( buildCfg ) )
return nil
}
2017-01-10 04:55:03 -05:00
require . NoError ( t , h . Build ( buildCfg ) )
return h . Sites [ 0 ]
}
func writeSourcesToSource ( t * testing . T , base string , fs * hugofs . Fs , sources ... source . ByteSource ) {
for _ , src := range sources {
writeSource ( t , fs , filepath . Join ( base , src . Name ) , string ( src . Content ) )
}
}