feat: add Static and StaticFS helpers for serving static files
One-liner static file serving: v.Static("/assets/", "./public") for
filesystem directories and v.StaticFS("/assets/", fsys) for embed.FS.
Both auto-normalize the URL prefix and disable directory listings.
This commit is contained in:
143
static_test.go
Normal file
143
static_test.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package via
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStatic(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
os.MkdirAll(filepath.Join(dir, "sub"), 0755)
|
||||
os.WriteFile(filepath.Join(dir, "hello.txt"), []byte("hello world"), 0644)
|
||||
os.WriteFile(filepath.Join(dir, "sub", "nested.txt"), []byte("nested"), 0644)
|
||||
|
||||
v := New()
|
||||
v.Static("/assets/", dir)
|
||||
|
||||
t.Run("serves file", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/assets/hello.txt", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "hello world", w.Body.String())
|
||||
})
|
||||
|
||||
t.Run("serves nested file", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/assets/sub/nested.txt", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "nested", w.Body.String())
|
||||
})
|
||||
|
||||
t.Run("directory listing returns 404", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/assets/", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
})
|
||||
|
||||
t.Run("subdirectory listing returns 404", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/assets/sub/", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
})
|
||||
|
||||
t.Run("missing file returns 404", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/assets/nope.txt", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStaticAutoSlash(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
os.WriteFile(filepath.Join(dir, "ok.txt"), []byte("ok"), 0644)
|
||||
|
||||
v := New()
|
||||
v.Static("/files", dir) // no trailing slash
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/files/ok.txt", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "ok", w.Body.String())
|
||||
}
|
||||
|
||||
func TestStaticFS(t *testing.T) {
|
||||
fsys := fstest.MapFS{
|
||||
"style.css": {Data: []byte("body{}")},
|
||||
"js/app.js": {Data: []byte("console.log('hi')")},
|
||||
}
|
||||
|
||||
v := New()
|
||||
v.StaticFS("/static/", fsys)
|
||||
|
||||
t.Run("serves file", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/static/style.css", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "body{}", w.Body.String())
|
||||
})
|
||||
|
||||
t.Run("serves nested file", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/static/js/app.js", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "console.log('hi')", w.Body.String())
|
||||
})
|
||||
|
||||
t.Run("directory listing returns 404", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/static/", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
})
|
||||
|
||||
t.Run("missing file returns 404", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/static/nope.css", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStaticFSAutoSlash(t *testing.T) {
|
||||
fsys := fstest.MapFS{
|
||||
"ok.txt": {Data: []byte("ok")},
|
||||
}
|
||||
|
||||
v := New()
|
||||
v.StaticFS("/embed", fsys) // no trailing slash
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/embed/ok.txt", nil)
|
||||
v.mux.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "ok", w.Body.String())
|
||||
}
|
||||
|
||||
// Verify StaticFS accepts the fs.FS interface (compile-time check).
|
||||
var _ fs.FS = fstest.MapFS{}
|
||||
Reference in New Issue
Block a user