add end-to-end test for guestbook view and user registration
This commit is contained in:
		
							parent
							
								
									1983662216
								
							
						
					
					
						commit
						d574dab3a7
					
				@ -1,6 +1,7 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -17,3 +18,43 @@ func TestPing(t *testing.T) {
 | 
				
			|||||||
	assert.Equal(t, code, http.StatusOK)
 | 
						assert.Equal(t, code, http.StatusOK)
 | 
				
			||||||
	assert.Equal(t, body, "OK")
 | 
						assert.Equal(t, body, "OK")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGetGuestbookView(t *testing.T) {
 | 
				
			||||||
 | 
						app := newTestApplication(t)
 | 
				
			||||||
 | 
						ts := newTestServer(t, app.routes())
 | 
				
			||||||
 | 
						defer ts.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							name     string
 | 
				
			||||||
 | 
							urlPath  string
 | 
				
			||||||
 | 
							wantCode int
 | 
				
			||||||
 | 
							wantBody string
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:     "Valid id",
 | 
				
			||||||
 | 
								urlPath:  fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(1)),
 | 
				
			||||||
 | 
								wantCode: http.StatusOK,
 | 
				
			||||||
 | 
								wantBody: "Guestbook for Example",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:     "Non-existent ID",
 | 
				
			||||||
 | 
								urlPath:  fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(2)),
 | 
				
			||||||
 | 
								wantCode: http.StatusNotFound,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:     "String ID",
 | 
				
			||||||
 | 
								urlPath:  "/websites/abcd/guestbook",
 | 
				
			||||||
 | 
								wantCode: http.StatusNotFound,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, tt := range tests {
 | 
				
			||||||
 | 
							t.Run(tt.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								code, _, body := ts.get(t, tt.urlPath)
 | 
				
			||||||
 | 
								assert.Equal(t, code, tt.wantCode)
 | 
				
			||||||
 | 
								if tt.wantBody != "" {
 | 
				
			||||||
 | 
									assert.StringContains(t, body, tt.wantBody)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										121
									
								
								cmd/web/handlers_user_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								cmd/web/handlers_user_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.32bit.cafe/32bitcafe/guestbook/internal/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestUserSignup(t *testing.T) {
 | 
				
			||||||
 | 
						app := newTestApplication(t)
 | 
				
			||||||
 | 
						ts := newTestServer(t, app.routes())
 | 
				
			||||||
 | 
						defer ts.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, _, body := ts.get(t, "/users/register")
 | 
				
			||||||
 | 
						validCSRFToken := extractCSRFToken(t, body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const (
 | 
				
			||||||
 | 
							validName     = "John"
 | 
				
			||||||
 | 
							validPassword = "validPassword"
 | 
				
			||||||
 | 
							validEmail    = "john@example.com"
 | 
				
			||||||
 | 
							formTag       = `<form action="/users/register" method="post">`
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							name         string
 | 
				
			||||||
 | 
							userName     string
 | 
				
			||||||
 | 
							userEmail    string
 | 
				
			||||||
 | 
							userPassword string
 | 
				
			||||||
 | 
							csrfToken    string
 | 
				
			||||||
 | 
							wantCode     int
 | 
				
			||||||
 | 
							wantFormTag  string
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:         "Valid submission",
 | 
				
			||||||
 | 
								userName:     validName,
 | 
				
			||||||
 | 
								userEmail:    validEmail,
 | 
				
			||||||
 | 
								userPassword: validPassword,
 | 
				
			||||||
 | 
								csrfToken:    validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:     http.StatusSeeOther,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:         "Missing token",
 | 
				
			||||||
 | 
								userName:     validName,
 | 
				
			||||||
 | 
								userEmail:    validEmail,
 | 
				
			||||||
 | 
								userPassword: validPassword,
 | 
				
			||||||
 | 
								wantCode:     http.StatusBadRequest,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:         "Empty name",
 | 
				
			||||||
 | 
								userName:     "",
 | 
				
			||||||
 | 
								userEmail:    validEmail,
 | 
				
			||||||
 | 
								userPassword: validPassword,
 | 
				
			||||||
 | 
								csrfToken:    validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:     http.StatusUnprocessableEntity,
 | 
				
			||||||
 | 
								wantFormTag:  formTag,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:         "Empty email",
 | 
				
			||||||
 | 
								userName:     validName,
 | 
				
			||||||
 | 
								userEmail:    "",
 | 
				
			||||||
 | 
								userPassword: validPassword,
 | 
				
			||||||
 | 
								csrfToken:    validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:     http.StatusUnprocessableEntity,
 | 
				
			||||||
 | 
								wantFormTag:  formTag,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:         "Empty password",
 | 
				
			||||||
 | 
								userName:     validName,
 | 
				
			||||||
 | 
								userEmail:    validEmail,
 | 
				
			||||||
 | 
								userPassword: "",
 | 
				
			||||||
 | 
								csrfToken:    validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:     http.StatusUnprocessableEntity,
 | 
				
			||||||
 | 
								wantFormTag:  formTag,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:         "Invalid email",
 | 
				
			||||||
 | 
								userName:     validName,
 | 
				
			||||||
 | 
								userEmail:    "asdfasdf",
 | 
				
			||||||
 | 
								userPassword: validPassword,
 | 
				
			||||||
 | 
								csrfToken:    validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:     http.StatusUnprocessableEntity,
 | 
				
			||||||
 | 
								wantFormTag:  formTag,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:         "Invalid password",
 | 
				
			||||||
 | 
								userName:     validName,
 | 
				
			||||||
 | 
								userEmail:    validEmail,
 | 
				
			||||||
 | 
								userPassword: "asdfasd",
 | 
				
			||||||
 | 
								csrfToken:    validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:     http.StatusUnprocessableEntity,
 | 
				
			||||||
 | 
								wantFormTag:  formTag,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:         "Duplicate email",
 | 
				
			||||||
 | 
								userName:     validName,
 | 
				
			||||||
 | 
								userEmail:    "dupe@example.com",
 | 
				
			||||||
 | 
								userPassword: validPassword,
 | 
				
			||||||
 | 
								csrfToken:    validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:     http.StatusUnprocessableEntity,
 | 
				
			||||||
 | 
								wantFormTag:  formTag,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, tt := range tests {
 | 
				
			||||||
 | 
							t.Run(tt.name, func(*testing.T) {
 | 
				
			||||||
 | 
								form := url.Values{}
 | 
				
			||||||
 | 
								form.Add("username", tt.userName)
 | 
				
			||||||
 | 
								form.Add("email", tt.userEmail)
 | 
				
			||||||
 | 
								form.Add("password", tt.userPassword)
 | 
				
			||||||
 | 
								form.Add("csrf_token", tt.csrfToken)
 | 
				
			||||||
 | 
								code, _, body := ts.postForm(t, "/users/register", form)
 | 
				
			||||||
 | 
								assert.Equal(t, code, tt.wantCode)
 | 
				
			||||||
 | 
								if tt.wantFormTag != "" {
 | 
				
			||||||
 | 
									assert.StringContains(t, body, tt.wantFormTag)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,17 +2,39 @@ package main
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
 | 
						"html"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"log/slog"
 | 
						"log/slog"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/http/cookiejar"
 | 
						"net/http/cookiejar"
 | 
				
			||||||
	"net/http/httptest"
 | 
						"net/http/httptest"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.32bit.cafe/32bitcafe/guestbook/internal/models/mocks"
 | 
				
			||||||
 | 
						"github.com/alexedwards/scs/v2"
 | 
				
			||||||
 | 
						"github.com/gorilla/schema"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newTestApplication(t *testing.T) *application {
 | 
					func newTestApplication(t *testing.T) *application {
 | 
				
			||||||
 | 
						formDecoder := schema.NewDecoder()
 | 
				
			||||||
 | 
						formDecoder.IgnoreUnknownKeys(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sessionManager := scs.New()
 | 
				
			||||||
 | 
						sessionManager.Lifetime = 12 * time.Hour
 | 
				
			||||||
 | 
						sessionManager.Cookie.Secure = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &application{
 | 
						return &application{
 | 
				
			||||||
		logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
 | 
							logger:            slog.New(slog.NewTextHandler(io.Discard, nil)),
 | 
				
			||||||
 | 
							sessionManager:    sessionManager,
 | 
				
			||||||
 | 
							websites:          &mocks.WebsiteModel{},
 | 
				
			||||||
 | 
							guestbooks:        &mocks.GuestbookModel{},
 | 
				
			||||||
 | 
							users:             &mocks.UserModel{},
 | 
				
			||||||
 | 
							guestbookComments: &mocks.GuestbookCommentModel{},
 | 
				
			||||||
 | 
							formDecoder:       formDecoder,
 | 
				
			||||||
 | 
							timezones:         getAvailableTimezones(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,3 +70,28 @@ func (ts *testServer) get(t *testing.T, urlPath string) (int, http.Header, strin
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return rs.StatusCode, rs.Header, string(body)
 | 
						return rs.StatusCode, rs.Header, string(body)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ts *testServer) postForm(t *testing.T, urlPath string, form url.Values) (int, http.Header, string) {
 | 
				
			||||||
 | 
						rs, err := ts.Client().PostForm(ts.URL+urlPath, form)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer rs.Body.Close()
 | 
				
			||||||
 | 
						body, err := io.ReadAll(rs.Body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						body = bytes.TrimSpace(body)
 | 
				
			||||||
 | 
						return rs.StatusCode, rs.Header, string(body)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var csrfTokenRX = regexp.MustCompile(`<input type="hidden" name="csrf_token" value="(.+?)">`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func extractCSRFToken(t *testing.T, body string) string {
 | 
				
			||||||
 | 
						matches := csrfTokenRX.FindStringSubmatch(body)
 | 
				
			||||||
 | 
						if len(matches) < 2 {
 | 
				
			||||||
 | 
							t.Fatal("no csrf token found in body")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return html.UnescapeString(matches[1])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								internal/assert/assert.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								internal/assert/assert.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					package assert
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Equal[T comparable](t *testing.T, actual, expected T) {
 | 
				
			||||||
 | 
						t.Helper()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if actual != expected {
 | 
				
			||||||
 | 
							t.Errorf("got: %v; want %v", actual, expected)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func StringContains(t *testing.T, actual, expectedSubstring string) {
 | 
				
			||||||
 | 
						t.Helper()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !strings.Contains(actual, expectedSubstring) {
 | 
				
			||||||
 | 
							t.Errorf("got: %q; expected to contain: %q", actual, expectedSubstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -24,6 +24,15 @@ type GuestbookCommentModel struct {
 | 
				
			|||||||
	DB *sql.DB
 | 
						DB *sql.DB
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GuestbookCommentModelInterface interface {
 | 
				
			||||||
 | 
						Insert(shortId uint64, guestbookId, parentId int64, authorName, authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error)
 | 
				
			||||||
 | 
						Get(shortId uint64) (GuestbookComment, error)
 | 
				
			||||||
 | 
						GetAll(guestbookId int64) ([]GuestbookComment, error)
 | 
				
			||||||
 | 
						GetDeleted(guestbookId int64) ([]GuestbookComment, error)
 | 
				
			||||||
 | 
						GetUnpublished(guestbookId int64) ([]GuestbookComment, error)
 | 
				
			||||||
 | 
						UpdateComment(comment *GuestbookComment) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName,
 | 
					func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName,
 | 
				
			||||||
	authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) {
 | 
						authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) {
 | 
				
			||||||
	stmt := `INSERT INTO guestbook_comments (ShortId, GuestbookId, ParentId, AuthorName,
 | 
						stmt := `INSERT INTO guestbook_comments (ShortId, GuestbookId, ParentId, AuthorName,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										66
									
								
								internal/models/mocks/guestbook.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								internal/models/mocks/guestbook.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					package mocks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.32bit.cafe/32bitcafe/guestbook/internal/models"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var mockGuestbook = models.Guestbook{
 | 
				
			||||||
 | 
						ID:        1,
 | 
				
			||||||
 | 
						ShortId:   1,
 | 
				
			||||||
 | 
						UserId:    1,
 | 
				
			||||||
 | 
						WebsiteId: 1,
 | 
				
			||||||
 | 
						Created:   time.Now(),
 | 
				
			||||||
 | 
						IsActive:  true,
 | 
				
			||||||
 | 
						Settings: models.GuestbookSettings{
 | 
				
			||||||
 | 
							IsCommentingEnabled:   true,
 | 
				
			||||||
 | 
							IsVisible:             true,
 | 
				
			||||||
 | 
							FilteredWords:         make([]string, 0),
 | 
				
			||||||
 | 
							AllowRemoteHostAccess: true,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GuestbookModel struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookModel) InitializeSettingsMap() error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookModel) Insert(shortId uint64, userId int64, websiteId int64, settings models.GuestbookSettings) (int64, error) {
 | 
				
			||||||
 | 
						return 2, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookModel) Get(shortId uint64) (models.Guestbook, error) {
 | 
				
			||||||
 | 
						switch shortId {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return mockGuestbook, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return models.Guestbook{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookModel) GetAll(userId int64) ([]models.Guestbook, error) {
 | 
				
			||||||
 | 
						switch userId {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return []models.Guestbook{mockGuestbook}, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return []models.Guestbook{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookModel) UpdateGuestbookSettings(guestbookId int64, settings models.GuestbookSettings) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookModel) UpdateSetting(guestbookId int64, setting models.Setting, value string) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookModel) AddFilteredWord(guestbookId int64, word string) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookModel) RemoveFilteredWord(guestbookId int64, word string) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										64
									
								
								internal/models/mocks/guestbookcomment.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								internal/models/mocks/guestbookcomment.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					package mocks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.32bit.cafe/32bitcafe/guestbook/internal/models"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var mockGuestbookComment = models.GuestbookComment{
 | 
				
			||||||
 | 
						ID:          1,
 | 
				
			||||||
 | 
						ShortId:     1,
 | 
				
			||||||
 | 
						GuestbookId: 1,
 | 
				
			||||||
 | 
						AuthorName:  "John Test",
 | 
				
			||||||
 | 
						AuthorEmail: "test@example.com",
 | 
				
			||||||
 | 
						AuthorSite:  "example.com",
 | 
				
			||||||
 | 
						CommentText: "Hello, world",
 | 
				
			||||||
 | 
						Created:     time.Now(),
 | 
				
			||||||
 | 
						IsPublished: true,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GuestbookCommentModel struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName,
 | 
				
			||||||
 | 
						authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) {
 | 
				
			||||||
 | 
						return 2, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookCommentModel) Get(shortId uint64) (models.GuestbookComment, error) {
 | 
				
			||||||
 | 
						switch shortId {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return mockGuestbookComment, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return models.GuestbookComment{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookCommentModel) GetAll(guestbookId int64) ([]models.GuestbookComment, error) {
 | 
				
			||||||
 | 
						switch guestbookId {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return []models.GuestbookComment{mockGuestbookComment}, nil
 | 
				
			||||||
 | 
						case 2:
 | 
				
			||||||
 | 
							return []models.GuestbookComment{}, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return []models.GuestbookComment{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookCommentModel) GetDeleted(guestbookId int64) ([]models.GuestbookComment, error) {
 | 
				
			||||||
 | 
						switch guestbookId {
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return []models.GuestbookComment{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookCommentModel) GetUnpublished(guestbookId int64) ([]models.GuestbookComment, error) {
 | 
				
			||||||
 | 
						switch guestbookId {
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return []models.GuestbookComment{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *GuestbookCommentModel) UpdateComment(comment *models.GuestbookComment) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										89
									
								
								internal/models/mocks/users.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								internal/models/mocks/users.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					package mocks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.32bit.cafe/32bitcafe/guestbook/internal/models"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var mockUser = models.User{
 | 
				
			||||||
 | 
						ID:       1,
 | 
				
			||||||
 | 
						ShortId:  1,
 | 
				
			||||||
 | 
						Username: "tester",
 | 
				
			||||||
 | 
						Email:    "test@example.com",
 | 
				
			||||||
 | 
						Deleted:  false,
 | 
				
			||||||
 | 
						IsBanned: false,
 | 
				
			||||||
 | 
						Created:  time.Now(),
 | 
				
			||||||
 | 
						Settings: mockUserSettings,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var mockUserSettings = models.UserSettings{
 | 
				
			||||||
 | 
						LocalTimezone: time.UTC,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type UserModel struct {
 | 
				
			||||||
 | 
						Settings map[string]models.Setting
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) InitializeSettingsMap() error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) Insert(shortId uint64, username string, email string, password string, settings models.UserSettings) error {
 | 
				
			||||||
 | 
						switch email {
 | 
				
			||||||
 | 
						case "dupe@example.com":
 | 
				
			||||||
 | 
							return models.ErrDuplicateEmail
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) Get(shortId uint64) (models.User, error) {
 | 
				
			||||||
 | 
						switch shortId {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return mockUser, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return models.User{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) GetById(id int64) (models.User, error) {
 | 
				
			||||||
 | 
						switch id {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return mockUser, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return models.User{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) GetAll() ([]models.User, error) {
 | 
				
			||||||
 | 
						return []models.User{mockUser}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) Authenticate(email, password string) (int64, error) {
 | 
				
			||||||
 | 
						if email == "test@example.com" && password == "password" {
 | 
				
			||||||
 | 
							return 1, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0, models.ErrInvalidCredentials
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) Exists(id int64) (bool, error) {
 | 
				
			||||||
 | 
						switch id {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) GetSettings(userId int64) (models.UserSettings, error) {
 | 
				
			||||||
 | 
						return mockUserSettings, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) UpdateUserSettings(userId int64, settings models.UserSettings) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *UserModel) UpdateSetting(userId int64, setting models.Setting, value string) error {
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										50
									
								
								internal/models/mocks/website.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								internal/models/mocks/website.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					package mocks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.32bit.cafe/32bitcafe/guestbook/internal/models"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var mockWebsite = models.Website{
 | 
				
			||||||
 | 
						ID:         1,
 | 
				
			||||||
 | 
						ShortId:    1,
 | 
				
			||||||
 | 
						Name:       "Example",
 | 
				
			||||||
 | 
						SiteUrl:    "example.com",
 | 
				
			||||||
 | 
						AuthorName: "John Test",
 | 
				
			||||||
 | 
						UserId:     1,
 | 
				
			||||||
 | 
						Created:    time.Now(),
 | 
				
			||||||
 | 
						Guestbook:  mockGuestbook,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type WebsiteModel struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *WebsiteModel) Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error) {
 | 
				
			||||||
 | 
						return 2, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *WebsiteModel) Get(shortId uint64) (models.Website, error) {
 | 
				
			||||||
 | 
						switch shortId {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return mockWebsite, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return models.Website{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *WebsiteModel) GetAllUser(userId int64) ([]models.Website, error) {
 | 
				
			||||||
 | 
						return []models.Website{mockWebsite}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *WebsiteModel) GetById(id int64) (models.Website, error) {
 | 
				
			||||||
 | 
						switch id {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return mockWebsite, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return models.Website{}, models.ErrNoRecord
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *WebsiteModel) GetAll() ([]models.Website, error) {
 | 
				
			||||||
 | 
						return []models.Website{mockWebsite}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -35,6 +35,19 @@ type UserModel struct {
 | 
				
			|||||||
	Settings map[string]Setting
 | 
						Settings map[string]Setting
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type UserModelInterface interface {
 | 
				
			||||||
 | 
						InitializeSettingsMap() error
 | 
				
			||||||
 | 
						Insert(shortId uint64, username string, email string, password string, settings UserSettings) error
 | 
				
			||||||
 | 
						Get(shortId uint64) (User, error)
 | 
				
			||||||
 | 
						GetById(id int64) (User, error)
 | 
				
			||||||
 | 
						GetAll() ([]User, error)
 | 
				
			||||||
 | 
						Authenticate(email, password string) (int64, error)
 | 
				
			||||||
 | 
						Exists(id int64) (bool, error)
 | 
				
			||||||
 | 
						GetSettings(userId int64) (UserSettings, error)
 | 
				
			||||||
 | 
						UpdateUserSettings(userId int64, settings UserSettings) error
 | 
				
			||||||
 | 
						UpdateSetting(userId int64, setting Setting, value string) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *UserModel) InitializeSettingsMap() error {
 | 
					func (m *UserModel) InitializeSettingsMap() error {
 | 
				
			||||||
	if m.Settings == nil {
 | 
						if m.Settings == nil {
 | 
				
			||||||
		m.Settings = make(map[string]Setting)
 | 
							m.Settings = make(map[string]Setting)
 | 
				
			||||||
 | 
				
			|||||||
@ -90,6 +90,14 @@ func (m *WebsiteModel) InitializeSettingsMap() error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type WebsiteModelInterface interface {
 | 
				
			||||||
 | 
						Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error)
 | 
				
			||||||
 | 
						Get(shortId uint64) (Website, error)
 | 
				
			||||||
 | 
						GetById(id int64) (Website, error)
 | 
				
			||||||
 | 
						GetAllUser(userId int64) ([]Website, error)
 | 
				
			||||||
 | 
						GetAll() ([]Website, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *WebsiteModel) Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error) {
 | 
					func (m *WebsiteModel) Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error) {
 | 
				
			||||||
	stmt := `INSERT INTO websites (ShortId, Name, SiteUrl, AuthorName, UserId, Created)
 | 
						stmt := `INSERT INTO websites (ShortId, Name, SiteUrl, AuthorName, UserId, Created)
 | 
				
			||||||
			VALUES (?, ?, ?, ?, ?, ?)`
 | 
								VALUES (?, ?, ?, ?, ?, ?)`
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user