github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/hugofs/rootmapping_fs_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 hugofs 15 16 import ( 17 "fmt" 18 "io/ioutil" 19 "path/filepath" 20 "sort" 21 "testing" 22 23 "github.com/gohugoio/hugo/hugofs/glob" 24 25 "github.com/gohugoio/hugo/config" 26 27 qt "github.com/frankban/quicktest" 28 "github.com/gohugoio/hugo/htesting" 29 "github.com/spf13/afero" 30 ) 31 32 func TestLanguageRootMapping(t *testing.T) { 33 c := qt.New(t) 34 v := config.New() 35 v.Set("contentDir", "content") 36 37 fs := NewBaseFileDecorator(afero.NewMemMapFs()) 38 39 c.Assert(afero.WriteFile(fs, filepath.Join("content/sv/svdir", "main.txt"), []byte("main sv"), 0755), qt.IsNil) 40 41 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/mysvblogcontent", "sv-f.txt"), []byte("some sv blog content"), 0755), qt.IsNil) 42 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/myenblogcontent", "en-f.txt"), []byte("some en blog content in a"), 0755), qt.IsNil) 43 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/mysvblogcontent/d1", "sv-d1-f.txt"), []byte("some sv blog content"), 0755), qt.IsNil) 44 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/myenblogcontent/d1", "en-d1-f.txt"), []byte("some en blog content in a"), 0755), qt.IsNil) 45 46 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/myotherenblogcontent", "en-f2.txt"), []byte("some en content"), 0755), qt.IsNil) 47 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/mysvdocs", "sv-docs.txt"), []byte("some sv docs content"), 0755), qt.IsNil) 48 c.Assert(afero.WriteFile(fs, filepath.Join("themes/b/myenblogcontent", "en-b-f.txt"), []byte("some en content"), 0755), qt.IsNil) 49 50 rfs, err := NewRootMappingFs(fs, 51 RootMapping{ 52 From: "content/blog", // Virtual path, first element is one of content, static, layouts etc. 53 To: "themes/a/mysvblogcontent", // Real path 54 Meta: &FileMeta{Lang: "sv"}, 55 }, 56 RootMapping{ 57 From: "content/blog", 58 To: "themes/a/myenblogcontent", 59 Meta: &FileMeta{Lang: "en"}, 60 }, 61 RootMapping{ 62 From: "content/blog", 63 To: "content/sv", 64 Meta: &FileMeta{Lang: "sv"}, 65 }, 66 RootMapping{ 67 From: "content/blog", 68 To: "themes/a/myotherenblogcontent", 69 Meta: &FileMeta{Lang: "en"}, 70 }, 71 RootMapping{ 72 From: "content/docs", 73 To: "themes/a/mysvdocs", 74 Meta: &FileMeta{Lang: "sv"}, 75 }, 76 ) 77 78 c.Assert(err, qt.IsNil) 79 80 collected, err := collectFilenames(rfs, "content", "content") 81 c.Assert(err, qt.IsNil) 82 c.Assert(collected, qt.DeepEquals, 83 []string{"blog/d1/en-d1-f.txt", "blog/d1/sv-d1-f.txt", "blog/en-f.txt", "blog/en-f2.txt", "blog/sv-f.txt", "blog/svdir/main.txt", "docs/sv-docs.txt"}, qt.Commentf("%#v", collected)) 84 85 dirs, err := rfs.Dirs(filepath.FromSlash("content/blog")) 86 c.Assert(err, qt.IsNil) 87 c.Assert(len(dirs), qt.Equals, 4) 88 for _, dir := range dirs { 89 f, err := dir.Meta().Open() 90 c.Assert(err, qt.IsNil) 91 f.Close() 92 } 93 94 blog, err := rfs.Open(filepath.FromSlash("content/blog")) 95 c.Assert(err, qt.IsNil) 96 fis, err := blog.Readdir(-1) 97 for _, fi := range fis { 98 f, err := fi.(FileMetaInfo).Meta().Open() 99 c.Assert(err, qt.IsNil) 100 f.Close() 101 } 102 blog.Close() 103 104 getDirnames := func(name string, rfs *RootMappingFs) []string { 105 c.Helper() 106 filename := filepath.FromSlash(name) 107 f, err := rfs.Open(filename) 108 c.Assert(err, qt.IsNil) 109 names, err := f.Readdirnames(-1) 110 111 f.Close() 112 c.Assert(err, qt.IsNil) 113 114 info, err := rfs.Stat(filename) 115 c.Assert(err, qt.IsNil) 116 f2, err := info.(FileMetaInfo).Meta().Open() 117 c.Assert(err, qt.IsNil) 118 names2, err := f2.Readdirnames(-1) 119 c.Assert(err, qt.IsNil) 120 c.Assert(names2, qt.DeepEquals, names) 121 f2.Close() 122 123 return names 124 } 125 126 rfsEn := rfs.Filter(func(rm RootMapping) bool { 127 return rm.Meta.Lang == "en" 128 }) 129 130 c.Assert(getDirnames("content/blog", rfsEn), qt.DeepEquals, []string{"d1", "en-f.txt", "en-f2.txt"}) 131 132 rfsSv := rfs.Filter(func(rm RootMapping) bool { 133 return rm.Meta.Lang == "sv" 134 }) 135 136 c.Assert(getDirnames("content/blog", rfsSv), qt.DeepEquals, []string{"d1", "sv-f.txt", "svdir"}) 137 138 // Make sure we have not messed with the original 139 c.Assert(getDirnames("content/blog", rfs), qt.DeepEquals, []string{"d1", "sv-f.txt", "en-f.txt", "svdir", "en-f2.txt"}) 140 141 c.Assert(getDirnames("content", rfsSv), qt.DeepEquals, []string{"blog", "docs"}) 142 c.Assert(getDirnames("content", rfs), qt.DeepEquals, []string{"blog", "docs"}) 143 } 144 145 func TestRootMappingFsDirnames(t *testing.T) { 146 c := qt.New(t) 147 fs := NewBaseFileDecorator(afero.NewMemMapFs()) 148 149 testfile := "myfile.txt" 150 c.Assert(fs.Mkdir("f1t", 0755), qt.IsNil) 151 c.Assert(fs.Mkdir("f2t", 0755), qt.IsNil) 152 c.Assert(fs.Mkdir("f3t", 0755), qt.IsNil) 153 c.Assert(afero.WriteFile(fs, filepath.Join("f2t", testfile), []byte("some content"), 0755), qt.IsNil) 154 155 rfs, err := newRootMappingFsFromFromTo("", fs, "static/bf1", "f1t", "static/cf2", "f2t", "static/af3", "f3t") 156 c.Assert(err, qt.IsNil) 157 158 fif, err := rfs.Stat(filepath.Join("static/cf2", testfile)) 159 c.Assert(err, qt.IsNil) 160 c.Assert(fif.Name(), qt.Equals, "myfile.txt") 161 fifm := fif.(FileMetaInfo).Meta() 162 c.Assert(fifm.Filename, qt.Equals, filepath.FromSlash("f2t/myfile.txt")) 163 164 root, err := rfs.Open("static") 165 c.Assert(err, qt.IsNil) 166 167 dirnames, err := root.Readdirnames(-1) 168 c.Assert(err, qt.IsNil) 169 c.Assert(dirnames, qt.DeepEquals, []string{"af3", "bf1", "cf2"}) 170 } 171 172 func TestRootMappingFsFilename(t *testing.T) { 173 c := qt.New(t) 174 workDir, clean, err := htesting.CreateTempDir(Os, "hugo-root-filename") 175 c.Assert(err, qt.IsNil) 176 defer clean() 177 fs := NewBaseFileDecorator(Os) 178 179 testfilename := filepath.Join(workDir, "f1t/foo/file.txt") 180 181 c.Assert(fs.MkdirAll(filepath.Join(workDir, "f1t/foo"), 0777), qt.IsNil) 182 c.Assert(afero.WriteFile(fs, testfilename, []byte("content"), 0666), qt.IsNil) 183 184 rfs, err := newRootMappingFsFromFromTo(workDir, fs, "static/f1", filepath.Join(workDir, "f1t"), "static/f2", filepath.Join(workDir, "f2t")) 185 c.Assert(err, qt.IsNil) 186 187 fi, err := rfs.Stat(filepath.FromSlash("static/f1/foo/file.txt")) 188 c.Assert(err, qt.IsNil) 189 fim := fi.(FileMetaInfo) 190 c.Assert(fim.Meta().Filename, qt.Equals, testfilename) 191 _, err = rfs.Stat(filepath.FromSlash("static/f1")) 192 c.Assert(err, qt.IsNil) 193 } 194 195 func TestRootMappingFsMount(t *testing.T) { 196 c := qt.New(t) 197 fs := NewBaseFileDecorator(afero.NewMemMapFs()) 198 199 testfile := "test.txt" 200 201 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/mynoblogcontent", testfile), []byte("some no content"), 0755), qt.IsNil) 202 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/myenblogcontent", testfile), []byte("some en content"), 0755), qt.IsNil) 203 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/mysvblogcontent", testfile), []byte("some sv content"), 0755), qt.IsNil) 204 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/mysvblogcontent", "other.txt"), []byte("some sv content"), 0755), qt.IsNil) 205 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/singlefiles", "no.txt"), []byte("no text"), 0755), qt.IsNil) 206 c.Assert(afero.WriteFile(fs, filepath.Join("themes/a/singlefiles", "sv.txt"), []byte("sv text"), 0755), qt.IsNil) 207 208 bfs := afero.NewBasePathFs(fs, "themes/a").(*afero.BasePathFs) 209 rm := []RootMapping{ 210 // Directories 211 { 212 From: "content/blog", 213 To: "mynoblogcontent", 214 Meta: &FileMeta{Lang: "no"}, 215 }, 216 { 217 From: "content/blog", 218 To: "myenblogcontent", 219 Meta: &FileMeta{Lang: "en"}, 220 }, 221 { 222 From: "content/blog", 223 To: "mysvblogcontent", 224 Meta: &FileMeta{Lang: "sv"}, 225 }, 226 // Files 227 { 228 From: "content/singles/p1.md", 229 To: "singlefiles/no.txt", 230 ToBasedir: "singlefiles", 231 Meta: &FileMeta{Lang: "no"}, 232 }, 233 { 234 From: "content/singles/p1.md", 235 To: "singlefiles/sv.txt", 236 ToBasedir: "singlefiles", 237 Meta: &FileMeta{Lang: "sv"}, 238 }, 239 } 240 241 rfs, err := NewRootMappingFs(bfs, rm...) 242 c.Assert(err, qt.IsNil) 243 244 blog, err := rfs.Stat(filepath.FromSlash("content/blog")) 245 c.Assert(err, qt.IsNil) 246 c.Assert(blog.IsDir(), qt.Equals, true) 247 blogm := blog.(FileMetaInfo).Meta() 248 c.Assert(blogm.Lang, qt.Equals, "no") // First match 249 250 f, err := blogm.Open() 251 c.Assert(err, qt.IsNil) 252 defer f.Close() 253 dirs1, err := f.Readdirnames(-1) 254 c.Assert(err, qt.IsNil) 255 // Union with duplicate dir names filtered. 256 c.Assert(dirs1, qt.DeepEquals, []string{"test.txt", "test.txt", "other.txt", "test.txt"}) 257 258 files, err := afero.ReadDir(rfs, filepath.FromSlash("content/blog")) 259 c.Assert(err, qt.IsNil) 260 c.Assert(len(files), qt.Equals, 4) 261 262 testfilefi := files[1] 263 c.Assert(testfilefi.Name(), qt.Equals, testfile) 264 265 testfilem := testfilefi.(FileMetaInfo).Meta() 266 c.Assert(testfilem.Filename, qt.Equals, filepath.FromSlash("themes/a/mynoblogcontent/test.txt")) 267 268 tf, err := testfilem.Open() 269 c.Assert(err, qt.IsNil) 270 defer tf.Close() 271 b, err := ioutil.ReadAll(tf) 272 c.Assert(err, qt.IsNil) 273 c.Assert(string(b), qt.Equals, "some no content") 274 275 // Ambiguous 276 _, err = rfs.Stat(filepath.FromSlash("content/singles/p1.md")) 277 c.Assert(err, qt.Not(qt.IsNil)) 278 279 singlesDir, err := rfs.Open(filepath.FromSlash("content/singles")) 280 c.Assert(err, qt.IsNil) 281 defer singlesDir.Close() 282 singles, err := singlesDir.Readdir(-1) 283 c.Assert(err, qt.IsNil) 284 c.Assert(singles, qt.HasLen, 2) 285 for i, lang := range []string{"no", "sv"} { 286 fi := singles[i].(FileMetaInfo) 287 c.Assert(fi.Meta().PathFile(), qt.Equals, filepath.FromSlash("themes/a/singlefiles/"+lang+".txt")) 288 c.Assert(fi.Meta().Lang, qt.Equals, lang) 289 c.Assert(fi.Name(), qt.Equals, "p1.md") 290 } 291 } 292 293 func TestRootMappingFsMountOverlap(t *testing.T) { 294 c := qt.New(t) 295 fs := NewBaseFileDecorator(afero.NewMemMapFs()) 296 297 c.Assert(afero.WriteFile(fs, filepath.FromSlash("da/a.txt"), []byte("some no content"), 0755), qt.IsNil) 298 c.Assert(afero.WriteFile(fs, filepath.FromSlash("db/b.txt"), []byte("some no content"), 0755), qt.IsNil) 299 c.Assert(afero.WriteFile(fs, filepath.FromSlash("dc/c.txt"), []byte("some no content"), 0755), qt.IsNil) 300 c.Assert(afero.WriteFile(fs, filepath.FromSlash("de/e.txt"), []byte("some no content"), 0755), qt.IsNil) 301 302 rm := []RootMapping{ 303 { 304 From: "static", 305 To: "da", 306 }, 307 { 308 From: "static/b", 309 To: "db", 310 }, 311 { 312 From: "static/b/c", 313 To: "dc", 314 }, 315 { 316 From: "/static/e/", 317 To: "de", 318 }, 319 } 320 321 rfs, err := NewRootMappingFs(fs, rm...) 322 c.Assert(err, qt.IsNil) 323 324 checkDirnames := func(name string, expect []string) { 325 c.Helper() 326 name = filepath.FromSlash(name) 327 f, err := rfs.Open(name) 328 c.Assert(err, qt.IsNil) 329 defer f.Close() 330 names, err := f.Readdirnames(-1) 331 c.Assert(err, qt.IsNil) 332 c.Assert(names, qt.DeepEquals, expect, qt.Commentf(fmt.Sprintf("%#v", names))) 333 } 334 335 checkDirnames("static", []string{"a.txt", "b", "e"}) 336 checkDirnames("static/b", []string{"b.txt", "c"}) 337 checkDirnames("static/b/c", []string{"c.txt"}) 338 339 fi, err := rfs.Stat(filepath.FromSlash("static/b/b.txt")) 340 c.Assert(err, qt.IsNil) 341 c.Assert(fi.Name(), qt.Equals, "b.txt") 342 } 343 344 func TestRootMappingFsOs(t *testing.T) { 345 c := qt.New(t) 346 fs := NewBaseFileDecorator(afero.NewOsFs()) 347 348 d, clean, err := htesting.CreateTempDir(fs, "hugo-root-mapping-os") 349 c.Assert(err, qt.IsNil) 350 defer clean() 351 352 testfile := "myfile.txt" 353 c.Assert(fs.Mkdir(filepath.Join(d, "f1t"), 0755), qt.IsNil) 354 c.Assert(fs.Mkdir(filepath.Join(d, "f2t"), 0755), qt.IsNil) 355 c.Assert(fs.Mkdir(filepath.Join(d, "f3t"), 0755), qt.IsNil) 356 357 // Deep structure 358 deepDir := filepath.Join(d, "d1", "d2", "d3", "d4", "d5") 359 c.Assert(fs.MkdirAll(deepDir, 0755), qt.IsNil) 360 for i := 1; i <= 3; i++ { 361 c.Assert(fs.MkdirAll(filepath.Join(d, "d1", "d2", "d3", "d4", fmt.Sprintf("d4-%d", i)), 0755), qt.IsNil) 362 c.Assert(afero.WriteFile(fs, filepath.Join(d, "d1", "d2", "d3", fmt.Sprintf("f-%d.txt", i)), []byte("some content"), 0755), qt.IsNil) 363 } 364 365 c.Assert(afero.WriteFile(fs, filepath.Join(d, "f2t", testfile), []byte("some content"), 0755), qt.IsNil) 366 367 // https://github.com/gohugoio/hugo/issues/6854 368 mystaticDir := filepath.Join(d, "mystatic", "a", "b", "c") 369 c.Assert(fs.MkdirAll(mystaticDir, 0755), qt.IsNil) 370 c.Assert(afero.WriteFile(fs, filepath.Join(mystaticDir, "ms-1.txt"), []byte("some content"), 0755), qt.IsNil) 371 372 rfs, err := newRootMappingFsFromFromTo( 373 d, 374 fs, 375 "static/bf1", filepath.Join(d, "f1t"), 376 "static/cf2", filepath.Join(d, "f2t"), 377 "static/af3", filepath.Join(d, "f3t"), 378 "static", filepath.Join(d, "mystatic"), 379 "static/a/b/c", filepath.Join(d, "d1", "d2", "d3"), 380 "layouts", filepath.Join(d, "d1"), 381 ) 382 383 c.Assert(err, qt.IsNil) 384 385 fif, err := rfs.Stat(filepath.Join("static/cf2", testfile)) 386 c.Assert(err, qt.IsNil) 387 c.Assert(fif.Name(), qt.Equals, "myfile.txt") 388 389 root, err := rfs.Open("static") 390 c.Assert(err, qt.IsNil) 391 392 dirnames, err := root.Readdirnames(-1) 393 c.Assert(err, qt.IsNil) 394 c.Assert(dirnames, qt.DeepEquals, []string{"a", "af3", "bf1", "cf2"}, qt.Commentf(fmt.Sprintf("%#v", dirnames))) 395 396 getDirnames := func(dirname string) []string { 397 dirname = filepath.FromSlash(dirname) 398 f, err := rfs.Open(dirname) 399 c.Assert(err, qt.IsNil) 400 defer f.Close() 401 dirnames, err := f.Readdirnames(-1) 402 c.Assert(err, qt.IsNil) 403 sort.Strings(dirnames) 404 return dirnames 405 } 406 407 c.Assert(getDirnames("static/a/b"), qt.DeepEquals, []string{"c"}) 408 c.Assert(getDirnames("static/a/b/c"), qt.DeepEquals, []string{"d4", "f-1.txt", "f-2.txt", "f-3.txt", "ms-1.txt"}) 409 c.Assert(getDirnames("static/a/b/c/d4"), qt.DeepEquals, []string{"d4-1", "d4-2", "d4-3", "d5"}) 410 411 all, err := collectFilenames(rfs, "static", "static") 412 c.Assert(err, qt.IsNil) 413 414 c.Assert(all, qt.DeepEquals, []string{"a/b/c/f-1.txt", "a/b/c/f-2.txt", "a/b/c/f-3.txt", "a/b/c/ms-1.txt", "cf2/myfile.txt"}) 415 416 fis, err := collectFileinfos(rfs, "static", "static") 417 c.Assert(err, qt.IsNil) 418 419 c.Assert(fis[9].Meta().PathFile(), qt.Equals, filepath.FromSlash("d1/d2/d3/f-1.txt")) 420 421 dirc := fis[3].Meta() 422 423 f, err := dirc.Open() 424 c.Assert(err, qt.IsNil) 425 defer f.Close() 426 fileInfos, err := f.Readdir(-1) 427 c.Assert(err, qt.IsNil) 428 sortFileInfos(fileInfos) 429 i := 0 430 for _, fi := range fileInfos { 431 if fi.IsDir() || fi.Name() == "ms-1.txt" { 432 continue 433 } 434 i++ 435 meta := fi.(FileMetaInfo).Meta() 436 c.Assert(meta.Filename, qt.Equals, filepath.Join(d, fmt.Sprintf("/d1/d2/d3/f-%d.txt", i))) 437 c.Assert(meta.PathFile(), qt.Equals, filepath.FromSlash(fmt.Sprintf("d1/d2/d3/f-%d.txt", i))) 438 } 439 440 _, err = rfs.Stat(filepath.FromSlash("layouts/d2/d3/f-1.txt")) 441 c.Assert(err, qt.IsNil) 442 _, err = rfs.Stat(filepath.FromSlash("layouts/d2/d3")) 443 c.Assert(err, qt.IsNil) 444 } 445 446 func TestRootMappingFsOsBase(t *testing.T) { 447 c := qt.New(t) 448 fs := NewBaseFileDecorator(afero.NewOsFs()) 449 450 d, clean, err := htesting.CreateTempDir(fs, "hugo-root-mapping-os-base") 451 c.Assert(err, qt.IsNil) 452 defer clean() 453 454 // Deep structure 455 deepDir := filepath.Join(d, "d1", "d2", "d3", "d4", "d5") 456 c.Assert(fs.MkdirAll(deepDir, 0755), qt.IsNil) 457 for i := 1; i <= 3; i++ { 458 c.Assert(fs.MkdirAll(filepath.Join(d, "d1", "d2", "d3", "d4", fmt.Sprintf("d4-%d", i)), 0755), qt.IsNil) 459 c.Assert(afero.WriteFile(fs, filepath.Join(d, "d1", "d2", "d3", fmt.Sprintf("f-%d.txt", i)), []byte("some content"), 0755), qt.IsNil) 460 } 461 462 mystaticDir := filepath.Join(d, "mystatic", "a", "b", "c") 463 c.Assert(fs.MkdirAll(mystaticDir, 0755), qt.IsNil) 464 c.Assert(afero.WriteFile(fs, filepath.Join(mystaticDir, "ms-1.txt"), []byte("some content"), 0755), qt.IsNil) 465 466 bfs := afero.NewBasePathFs(fs, d) 467 468 rfs, err := newRootMappingFsFromFromTo( 469 "", 470 bfs, 471 "static", "mystatic", 472 "static/a/b/c", filepath.Join("d1", "d2", "d3"), 473 ) 474 475 getDirnames := func(dirname string) []string { 476 dirname = filepath.FromSlash(dirname) 477 f, err := rfs.Open(dirname) 478 c.Assert(err, qt.IsNil) 479 defer f.Close() 480 dirnames, err := f.Readdirnames(-1) 481 c.Assert(err, qt.IsNil) 482 sort.Strings(dirnames) 483 return dirnames 484 } 485 486 c.Assert(getDirnames("static/a/b/c"), qt.DeepEquals, []string{"d4", "f-1.txt", "f-2.txt", "f-3.txt", "ms-1.txt"}) 487 } 488 489 func TestRootMappingFileFilter(t *testing.T) { 490 c := qt.New(t) 491 fs := NewBaseFileDecorator(afero.NewMemMapFs()) 492 493 for _, lang := range []string{"no", "en", "fr"} { 494 for i := 1; i <= 3; i++ { 495 c.Assert(afero.WriteFile(fs, filepath.Join(lang, fmt.Sprintf("my%s%d.txt", lang, i)), []byte("some text file for"+lang), 0755), qt.IsNil) 496 } 497 } 498 499 for _, lang := range []string{"no", "en", "fr"} { 500 for i := 1; i <= 3; i++ { 501 c.Assert(afero.WriteFile(fs, filepath.Join(lang, "sub", fmt.Sprintf("mysub%s%d.txt", lang, i)), []byte("some text file for"+lang), 0755), qt.IsNil) 502 } 503 } 504 505 rm := []RootMapping{ 506 { 507 From: "content", 508 To: "no", 509 Meta: &FileMeta{Lang: "no", InclusionFilter: glob.MustNewFilenameFilter(nil, []string{"**.txt"})}, 510 }, 511 { 512 From: "content", 513 To: "en", 514 Meta: &FileMeta{Lang: "en"}, 515 }, 516 { 517 From: "content", 518 To: "fr", 519 Meta: &FileMeta{Lang: "fr", InclusionFilter: glob.MustNewFilenameFilter(nil, []string{"**.txt"})}, 520 }, 521 } 522 523 rfs, err := NewRootMappingFs(fs, rm...) 524 c.Assert(err, qt.IsNil) 525 526 assertExists := func(filename string, shouldExist bool) { 527 c.Helper() 528 filename = filepath.Clean(filename) 529 _, err1 := rfs.Stat(filename) 530 f, err2 := rfs.Open(filename) 531 if shouldExist { 532 c.Assert(err1, qt.IsNil) 533 c.Assert(err2, qt.IsNil) 534 c.Assert(f.Close(), qt.IsNil) 535 } else { 536 c.Assert(err1, qt.Not(qt.IsNil)) 537 c.Assert(err2, qt.Not(qt.IsNil)) 538 } 539 } 540 541 assertExists("content/myno1.txt", false) 542 assertExists("content/myen1.txt", true) 543 assertExists("content/myfr1.txt", false) 544 545 dirEntriesSub, err := afero.ReadDir(rfs, filepath.Join("content", "sub")) 546 c.Assert(err, qt.IsNil) 547 c.Assert(len(dirEntriesSub), qt.Equals, 3) 548 549 dirEntries, err := afero.ReadDir(rfs, "content") 550 551 c.Assert(err, qt.IsNil) 552 c.Assert(len(dirEntries), qt.Equals, 4) 553 554 }