Skip to content

Commit 41e35a9

Browse files
committed
testing middleware
1 parent 7e779d5 commit 41e35a9

File tree

9 files changed

+123
-15
lines changed

9 files changed

+123
-15
lines changed

cmd/config/templates.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package config
33
import (
44
"github.com/justinas/nosurf"
55
"html/template"
6+
"io/fs"
67
"net/http"
78
"path/filepath"
89
"snippetbox.pethron.me/internal/models"
10+
"snippetbox.pethron.me/ui"
911
"time"
1012
)
1113

@@ -20,7 +22,10 @@ type TemplateData struct {
2022
}
2123

2224
func humanDate(t time.Time) string {
23-
return t.Format("02 Jan 2006 at 15:04")
25+
if t.IsZero() {
26+
return ""
27+
}
28+
return t.UTC().Format("02 Jan 2006 at 15:04")
2429
}
2530

2631
var functions = template.FuncMap{
@@ -35,30 +40,27 @@ func NewTemplateCache() (map[string]*template.Template, error) {
3540
// match the pattern "./ui/html/pages/*.tmpl". This will essentially gives
3641
// us a slice of all the filepaths for our application 'page' templates
3742
// like: [ui/html/pages/home.tmpl ui/html/pages/view.tmpl]
38-
pages, err := filepath.Glob("./ui/html/pages/*.tmpl")
43+
pages, err := fs.Glob(ui.Files, "html/pages/*.tmpl")
3944
if err != nil {
45+
4046
return nil, err
4147
}
4248

4349
// Loop through the page filepaths one-by-one.
4450
for _, page := range pages {
4551
name := filepath.Base(page)
4652

47-
ts, err := template.New(name).Funcs(functions).ParseFiles("./ui/html/base.tmpl")
48-
if err != nil {
49-
return nil, err
53+
patterns := []string{
54+
"html/base.tmpl",
55+
"html/partials/*.tmpl",
56+
page,
5057
}
5158

52-
ts, err = ts.ParseGlob("./ui/html/partials/*.tmpl")
59+
ts, err := template.New(name).Funcs(functions).ParseFS(ui.Files,
60+
patterns...)
5361
if err != nil {
5462
return nil, err
5563
}
56-
57-
ts, err = ts.ParseFiles(page)
58-
if err != nil {
59-
return nil, err
60-
}
61-
6264
cache[name] = ts
6365
}
6466

cmd/config/templates_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package config
2+
3+
import (
4+
"snippetbox.pethron.me/internal/assert"
5+
"testing"
6+
"time"
7+
)
8+
9+
func TestHumanDate(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
tm time.Time
13+
want string
14+
}{
15+
{
16+
name: "UTC",
17+
tm: time.Date(2022, 3, 17, 10, 15, 0, 0, time.UTC),
18+
want: "17 Mar 2022 at 10:15",
19+
}, {
20+
name: "Empty",
21+
tm: time.Time{},
22+
want: "",
23+
}, {
24+
name: "CET",
25+
tm: time.Date(2022, 3, 17, 10, 15, 0, 0, time.FixedZone("CET", 1*60*60)),
26+
want: "17 Mar 2022 at 09:15",
27+
},
28+
}
29+
for _, tt := range tests {
30+
t.Run(tt.name, func(t *testing.T) {
31+
hd := humanDate(tt.tm)
32+
// Use the new assert.Equal() helper to compare the expected and
33+
// actual values.
34+
assert.Equal(t, hd, tt.want)
35+
})
36+
}
37+
}

cmd/web/handlers.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func snippetCreatePost(app *config.Application) http.HandlerFunc {
8484
form.CheckField(validator.NotBlank(form.Title), "title", "This field cannot be blank")
8585
form.CheckField(validator.MaxChars(form.Title, 100), "title", "This field cannot be more than 100 characters long")
8686
form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank")
87-
form.CheckField(validator.PermittedInt(form.Expires, 1, 7, 365), "expires", "This field must equal 1, 7 or 365")
87+
form.CheckField(validator.PermittedValue(form.Expires, 1, 7, 365), "expires", "This field must equal 1, 7 or 365")
8888

8989
if !form.Valid() {
9090
data := app.NewTemplateData(r)
@@ -235,3 +235,7 @@ func userLogoutPost(app *config.Application) http.HandlerFunc {
235235
http.Redirect(w, r, "/", http.StatusSeeOther)
236236
}
237237
}
238+
239+
func ping(w http.ResponseWriter, r *http.Request) {
240+
w.Write([]byte("OK"))
241+
}

cmd/web/handlers_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"net/http"
7+
"net/http/httptest"
8+
"snippetbox.pethron.me/internal/assert"
9+
"testing"
10+
)
11+
12+
func TestPing(t *testing.T) {
13+
// Initialize a new httptest.ResponseRecorder.
14+
rr := httptest.NewRecorder()
15+
// Initialize a new dummy http.Request.
16+
r, err := http.NewRequest(http.MethodGet, "/", nil)
17+
if err != nil {
18+
t.Fatal(err)
19+
}
20+
// Call the ping handler function, passing in the
21+
// httptest.ResponseRecorder and http.Request.
22+
ping(rr, r)
23+
// Call the Result() method on the http.ResponseRecorder to get the
24+
// http.Response generated by the ping handler.
25+
rs := rr.Result()
26+
// Check that the status code written by the ping handler was 200.
27+
assert.Equal(t, rs.StatusCode, http.StatusOK)
28+
// And we can check that the response body written by the ping handler
29+
// equals "OK".
30+
defer rs.Body.Close()
31+
body, err := io.ReadAll(rs.Body)
32+
if err != nil {
33+
t.Fatal(err)
34+
}
35+
bytes.TrimSpace(body)
36+
assert.Equal(t, string(body), "OK")
37+
}

cmd/web/routes.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"github.com/justinas/alice"
66
"net/http"
77
"snippetbox.pethron.me/cmd/config"
8+
"snippetbox.pethron.me/ui"
89
)
910

1011
func routes(app *config.Application) func() http.Handler {
@@ -15,9 +16,9 @@ func routes(app *config.Application) func() http.Handler {
1516
app.NotFoundError(w)
1617
})
1718

18-
fileServer := http.FileServer(http.Dir("./ui/static/"))
19+
fileServer := http.FileServer(http.FS(ui.Files))
1920

20-
router.Handler(http.MethodGet, "/static/*filepath", http.StripPrefix("/static", fileServer))
21+
router.Handler(http.MethodGet, "/static/*filepath", fileServer)
2122

2223
// unprotected
2324
dynamic := alice.New(app.SessionManager.LoadAndSave, noSurf, Authenticate(app))

internal/assert/assert.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package assert
2+
3+
import "testing"
4+
5+
func Equal[T comparable](t *testing.T, actual, expected T) {
6+
t.Helper()
7+
if actual != expected {
8+
t.Errorf("got: %v; want: %v", actual, expected)
9+
}
10+
}

internal/validator/validator.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ func PermittedInt(value int, permittedValues ...int) bool {
7070
return false
7171
}
7272

73+
func PermittedValue[T comparable](value T, permittedValues ...T) bool {
74+
for i := range permittedValues {
75+
if value == permittedValues[i] {
76+
return true
77+
}
78+
}
79+
return false
80+
}
81+
7382
// Matches returns true if a value matches a provided compiled regular
7483
// expression pattern.
7584
func Matches(value string, rx *regexp.Regexp) bool {

tmp/web

10.9 MB
Binary file not shown.

ui/efs.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package ui
2+
3+
import (
4+
"embed"
5+
)
6+
7+
//go:embed "html" "static"
8+
var Files embed.FS

0 commit comments

Comments
 (0)