Compare commits

..

3 Commits

Author SHA1 Message Date
Muyao CHEN
0c0159734e Add run script 2024-07-02 21:52:22 +02:00
Muyao CHEN
d87d8ed594 Writing tests for the Forms package 2024-07-02 21:48:00 +02:00
Muyao CHEN
875be55076 Writing tests for Render package 2024-07-02 13:57:45 +02:00
8 changed files with 295 additions and 26 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
**/c.out
**/c.html
bookings

View File

@ -2,7 +2,6 @@ package forms
import (
"fmt"
"net/http"
"net/url"
"strings"
@ -25,18 +24,18 @@ func New(data url.Values) *Form {
// Required checks required fields
func (f *Form) Required(fields ...string) {
for _, field := range fields {
value := f.Get(field)
if strings.TrimSpace(value) == "" {
f.Errors.Add(field, "This field cannot be blank")
}
}
for _, field := range fields {
value := f.Get(field)
if strings.TrimSpace(value) == "" {
f.Errors.Add(field, "This field cannot be blank")
}
}
}
// Has checks if form field is in post and not emtpy
func (f *Form) Has(field string, r *http.Request) bool {
x := r.Form.Get(field)
return x != ""
func (f *Form) Has(field string) bool {
x := f.Get(field)
return x != ""
}
// Valid returns true if there are no errors, otherwise false
@ -45,19 +44,19 @@ func (f *Form) Valid() bool {
}
// MinLength checks for string minimum length
func (f *Form) MinLength(field string, length int, r *http.Request) bool {
value := r.Form.Get(field)
if len(value) < length {
f.Errors.Add(field, fmt.Sprintf("This field must have at least %d letters", length))
return false
}
return true
func (f *Form) MinLength(field string, length int) bool {
value := f.Get(field)
if len(value) < length {
f.Errors.Add(field, fmt.Sprintf("This field must have at least %d letters", length))
return false
}
return true
}
// IsEmail checks the email address
func (f *Form) IsEmail(field string, r *http.Request) {
value := r.Form.Get(field)
if !govalidator.IsEmail(value) {
f.Errors.Add(field, "Invalid email address")
}
func (f *Form) IsEmail(field string) {
value := f.Get(field)
if !govalidator.IsEmail(value) {
f.Errors.Add(field, "Invalid email address")
}
}

View File

@ -0,0 +1,131 @@
package forms
import (
"net/http/httptest"
"net/url"
"testing"
)
func TestForms_Valid(t *testing.T) {
r := httptest.NewRequest("POST", "/test-url", nil)
form := New(r.PostForm)
isValid := form.Valid()
if !isValid {
t.Error("got invalid when should have been valid")
}
}
func TestForms_Required(t *testing.T) {
r := httptest.NewRequest("POST", "/test-url", nil)
form := New(r.PostForm)
form.Required("a", "b", "c")
if form.Valid() {
t.Error("required fields are not given, should be invalid")
}
postData := url.Values{}
postData.Add("a", "a")
postData.Add("b", "a")
postData.Add("c", "a")
r = httptest.NewRequest("POST", "/test-url", nil)
r.PostForm = postData
form = New(r.PostForm)
form.Required("a", "b", "c")
if !form.Valid() {
t.Error("required fields are given, should be valid")
}
}
func TestForms_Has(t *testing.T) {
postData := url.Values{}
form := New(postData)
if form.Has("a") {
t.Error("the field should not exist")
}
postData = url.Values{}
postData.Add("a", "a")
form = New(postData)
if !form.Has("a") {
t.Error("the field should exist")
}
}
func TestForms_MinLength(t *testing.T) {
postData := url.Values{}
form := New(postData)
if form.MinLength("a", 3) {
t.Error("the field should not exist")
}
errMsg := form.Errors.Get("a")
if errMsg != "This field must have at least 3 letters" {
t.Error("should have an errMsg")
}
if form.Valid() {
t.Error("should be invalid")
}
postData = url.Values{}
postData.Add("a", "ab")
postData.Add("b", "abc")
form = New(postData)
if form.MinLength("a", 3) {
t.Error("the field is shorter than 3 chars")
}
if !form.MinLength("b", 3) {
t.Error("the field is equal to 3 chars")
}
if form.Valid() {
t.Error("should be invalid")
}
}
func TestForms_IsEmail(t *testing.T) {
postData := url.Values{}
form := New(postData)
form.IsEmail("a")
if form.Valid() {
t.Error("email should not exit")
}
postData = url.Values{}
postData.Add("a", "a@a.com")
form = New(postData)
form.IsEmail("a")
errMsg := form.Errors.Get("a")
if errMsg != "" {
t.Error("should not have an errMsg")
}
if !form.Valid() {
t.Error("should be a valid email")
}
postData = url.Values{}
postData.Add("a", "a@.com")
form = New(postData)
form.IsEmail("a")
if form.Valid() {
t.Error("Should not be a valid email")
}
}

View File

@ -100,8 +100,8 @@ func (m *Repository) PostMakeReservation(w http.ResponseWriter, r *http.Request)
form := forms.New(r.PostForm)
form.Required("first_name", "last_name", "email")
form.MinLength("first_name", 2, r)
form.IsEmail("email", r)
form.MinLength("first_name", 2)
form.IsEmail("email")
if !form.Valid() {
data := make(map[string]interface{})

View File

@ -2,6 +2,7 @@ package render
import (
"bytes"
"errors"
"fmt"
"go-udemy-web-1/internal/config"
"go-udemy-web-1/internal/models"
@ -35,7 +36,7 @@ func AddDefaultData(td *models.TemplateData, r *http.Request) *models.TemplateDa
}
// RenderTemplate renders a HTML template file
func RenderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, td *models.TemplateData) {
func RenderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, td *models.TemplateData) error {
var tc map[string]*template.Template
if app.UseCache {
// get the template cache from the app config
@ -47,7 +48,7 @@ func RenderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, td *mod
// get requested template from cache
t, ok := tc[tmpl]
if !ok {
log.Fatal("Could not get template from template cache")
return errors.New("could not get template from template cache")
}
// Write to a buffer to make sure that the template can be read and
@ -59,13 +60,17 @@ func RenderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, td *mod
err := t.Execute(buf, td)
if err != nil {
log.Println(err)
return err
}
// render the template
_, err = buf.WriteTo(w)
if err != nil {
log.Println(err)
return err
}
return nil
}
func CreateTemplateCache() (map[string]*template.Template, error) {

View File

@ -0,0 +1,76 @@
package render
import (
"go-udemy-web-1/internal/models"
"net/http"
"testing"
)
func TestAddDefaultData(t *testing.T) {
var td models.TemplateData
r, err := getSession()
if err != nil {
t.Error(err)
}
session.Put(r.Context(), "flash", "123")
result := AddDefaultData(&td, r)
if result.Flash != "123" {
t.Error("flash value of 123 not found in session")
}
}
func TestRenderTemplate(t *testing.T) {
pathToTemplates = "../../templates"
tc, err := CreateTemplateCache()
if err != nil {
t.Error(err)
}
app.TemplateCahce = tc
r, err := getSession()
if err != nil {
t.Error(err)
}
var ww myWriter
err = RenderTemplate(&ww, r, "home.page.tmpl", &models.TemplateData{})
if err != nil {
t.Error("error writiing template to browser")
}
err = RenderTemplate(&ww, r, "non-existent.page.html", &models.TemplateData{})
if err == nil {
t.Error("rendered template that doesn't exist")
}
}
func getSession() (*http.Request, error) {
r, err := http.NewRequest("GET", "/some-url", nil)
if err != nil {
return nil, err
}
ctx := r.Context()
ctx, _ = session.Load(ctx, r.Header.Get("X-Session"))
r = r.WithContext(ctx)
return r, nil
}
func TestNewTemplate(t *testing.T) {
NewTemplates(app)
}
func TestCreateTemplateCache(t *testing.T) {
pathToTemplates = "../../templates"
_, err := CreateTemplateCache()
if err != nil {
t.Error(err)
}
}

View File

@ -0,0 +1,52 @@
package render
import (
"encoding/gob"
"go-udemy-web-1/internal/config"
"go-udemy-web-1/internal/models"
"net/http"
"os"
"testing"
"time"
"github.com/alexedwards/scs/v2"
)
var (
session *scs.SessionManager
testApp config.AppConfig
)
func TestMain(m *testing.M) {
// what am I going to put in the session
gob.Register(models.Reservation{})
// change this to true when in production
testApp.InProduction = false
session = scs.New()
session.Lifetime = 24 * time.Hour
session.Cookie.Persist = true
session.Cookie.SameSite = http.SameSiteLaxMode
session.Cookie.Secure = testApp.InProduction
testApp.Session = session
app = &testApp
os.Exit(m.Run())
}
type myWriter struct{}
func (tw *myWriter) Header() http.Header {
var h http.Header
return h
}
func (tw *myWriter) WriteHeader(i int) {}
func (tw *myWriter) Write(b []byte) (int, error) {
length := len(b)
return length, nil
}

3
run.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
go build -o bookings cmd/web/*go && ./bookings