From b467258664af70a1650a9f24b237f8ab5ca86a4f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 11 Nov 2021 21:10:54 +0800 Subject: [PATCH] Support use io/fs.FS directly (#97) --- fs_embed.go | 30 ++++++++++++++++++ fs_test.go | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 fs_test.go diff --git a/fs_embed.go b/fs_embed.go index 5dd2d2b..d5169db 100644 --- a/fs_embed.go +++ b/fs_embed.go @@ -1,9 +1,11 @@ +//go:build go1.16 // +build go1.16 package render import ( "embed" + "io" "io/fs" "path/filepath" ) @@ -29,3 +31,31 @@ func (e *EmbedFileSystem) Walk(root string, walkFn filepath.WalkFunc) error { return walkFn(path, info, err) }) } + +type tmplFS struct { + fs.FS +} + +func (tfs tmplFS) Walk(root string, walkFn filepath.WalkFunc) error { + return fs.WalkDir(tfs, root, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + info, err := d.Info() + return walkFn(path, info, err) + }) +} + +func (tfs tmplFS) ReadFile(filename string) ([]byte, error) { + f, err := tfs.Open(filename) + if err != nil { + return nil, err + } + defer f.Close() + return io.ReadAll(f) +} + +// FS converts io/fs.FS to FileSystem +func FS(oriFS fs.FS) FileSystem { + return tmplFS{oriFS} +} diff --git a/fs_test.go b/fs_test.go new file mode 100644 index 0000000..ebbf067 --- /dev/null +++ b/fs_test.go @@ -0,0 +1,91 @@ +//go:build go1.16 +// +build go1.16 + +package render + +import ( + "net/http" + "net/http/httptest" + "os" + "testing" +) + +func TestIOFSEmbedTemplateLookup(t *testing.T) { + baseDir := "testdata/template-dir-test" + fname0Rel := "0" + fname1Rel := "subdir/1" + fnameShouldParsedRel := "dedicated.tmpl/notbad" + dirShouldNotParsedRel := "dedicated" + + r := New(Options{ + Directory: baseDir, + Extensions: []string{".tmpl", ".html"}, + FileSystem: FS(EmbedFixtures), + }) + + expect(t, r.TemplateLookup(fname1Rel) != nil, true) + expect(t, r.TemplateLookup(fname0Rel) != nil, true) + expect(t, r.TemplateLookup(fnameShouldParsedRel) != nil, true) + expect(t, r.TemplateLookup(dirShouldNotParsedRel) == nil, true) +} + +func TestIOFSDirTemplateLookup(t *testing.T) { + baseDir := "testdata/template-dir-test" + fname0Rel := "0" + fname1Rel := "subdir/1" + fnameShouldParsedRel := "dedicated.tmpl/notbad" + dirShouldNotParsedRel := "dedicated" + + r := New(Options{ + Directory: ".", + Extensions: []string{".tmpl", ".html"}, + FileSystem: FS(os.DirFS(baseDir)), + }) + + expect(t, r.TemplateLookup(fname1Rel) != nil, true) + expect(t, r.TemplateLookup(fname0Rel) != nil, true) + expect(t, r.TemplateLookup(fnameShouldParsedRel) != nil, true) + expect(t, r.TemplateLookup(dirShouldNotParsedRel) == nil, true) +} + +func TestIOFSEmbedHTMLBasic(t *testing.T) { + render := New(Options{ + Directory: "testdata/basic", + FileSystem: FS(EmbedFixtures), + }) + + var err error + h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err = render.HTML(w, http.StatusOK, "hello", "gophers") + }) + + res := httptest.NewRecorder() + req, _ := http.NewRequestWithContext(ctx, "GET", "/foo", nil) + h.ServeHTTP(res, req) + + expectNil(t, err) + expect(t, res.Code, 200) + expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8") + expect(t, res.Body.String(), "

Hello gophers

\n") +} + +func TestIOFSDirHTMLBasic(t *testing.T) { + render := New(Options{ + Directory: ".", + FileSystem: FS(os.DirFS("testdata/basic")), + }) + + var err error + h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err = render.HTML(w, http.StatusOK, "hello", "gophers") + }) + + res := httptest.NewRecorder() + req, _ := http.NewRequestWithContext(ctx, "GET", "/foo", nil) + h.ServeHTTP(res, req) + + expectNil(t, err) + expect(t, res.Code, 200) + expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8") + expect(t, res.Body.String(), "

Hello gophers

\n") +}