Skip to content

Commit

Permalink
Add a large amount of tests
Browse files Browse the repository at this point in the history
Signed-off-by: Jo Vandeginste <[email protected]>
  • Loading branch information
jovandeginste committed Feb 27, 2024
1 parent e188e24 commit 159c7ef
Show file tree
Hide file tree
Showing 16 changed files with 270 additions and 79 deletions.
57 changes: 25 additions & 32 deletions pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (

"github.com/alexedwards/scs/v2"
"github.com/cat-dealer/go-rand/v2"
"github.com/fsouza/slognil"
"github.com/jovandeginste/workout-tracker/pkg/database"
"github.com/labstack/echo/v4"
"github.com/lmittmann/tint"
"github.com/mattn/go-isatty"
"golang.org/x/text/language"
"gorm.io/gorm"

"github.com/vorlif/spreak"
Expand Down Expand Up @@ -55,28 +55,6 @@ func (a *App) jwtSecret() []byte {
return []byte(a.Config.JWTEncryptionKey)
}

func (a *App) ConfigureLocalizer() error {
bundle, err := spreak.NewBundle(
// Set the language used in the program code/templates
spreak.WithSourceLanguage(language.English),
// Set the path from which the translations should be loaded
spreak.WithDomainFs(spreak.NoDomain, a.Translations),
// Specify the languages you want to load
spreak.WithLanguage(translations()...),
)
if err != nil {
return err
}

a.translator = bundle

a.humanizer = humanize.MustNew(
humanize.WithLocale(humanLocales()...),
)

return nil
}

func (a *App) Serve() error {
go a.BackgroundWorker()

Expand All @@ -90,6 +68,8 @@ func (a *App) Configure() error {
return err
}

a.ConfigureLogger()

if err := a.ConfigureLocalizer(); err != nil {
return err
}
Expand Down Expand Up @@ -131,7 +111,15 @@ func (a *App) ConfigureDatabase() error {
return a.createAdminUser()
}

func newLogger() slog.Handler {
func newLogger(enabled bool) *slog.Logger {
if !enabled {
return slognil.NewLogger()
}

return slog.New(newLogHandler())
}

func newLogHandler() slog.Handler {
w := os.Stdout
if isatty.IsTerminal(w.Fd()) {
return tint.NewHandler(os.Stdout, &tint.Options{
Expand All @@ -143,17 +131,22 @@ func newLogger() slog.Handler {
return slog.NewJSONHandler(w, nil)
}

func NewApp(version Version) *App {
logger := slog.New(newLogger()).
With("app", "workout-tracker", "version", version.RefName, "sha", version.Sha)
func (a *App) ConfigureLogger() {
logger := newLogger(a.Config.Logging).
With("app", "workout-tracker").
With("version", a.Version.RefName).
With("sha", a.Version.Sha)

a := &App{
rawLogger: logger,
logger: logger.With("module", "app"),
a.rawLogger = logger
a.logger = logger.With("module", "app")
}

func NewApp(version Version) *App {
return &App{
Version: version,
logger: newLogger(false),
rawLogger: newLogger(false),
}

return a
}

func (a *App) createAdminUser() error {
Expand Down
88 changes: 88 additions & 0 deletions pkg/app/app_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package app

import (
"embed"
"log/slog"
"testing"

"github.com/fsouza/slognil"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var (
//go:embed test_assets/*
assetsFS embed.FS
AssetsFS = echo.MustSubFS(assetsFS, "assets")

//go:embed test_views/*
viewsFS embed.FS
ViewsFS = echo.MustSubFS(viewsFS, "views")

//go:embed test_translations/*
translationsFS embed.FS
TranslationsFS = echo.MustSubFS(translationsFS, "translations")
)

func defaultApp(t *testing.T) *App {
t.Setenv("WT_LOGGING", "false")

a := NewApp(Version{RefName: "test"})

a.Assets = AssetsFS
a.Views = ViewsFS
a.Translations = TranslationsFS

return a
}

func TestApp_RandomJWTError(t *testing.T) {
a1 := defaultApp(t)
s1 := a1.jwtSecret()
assert.NotEmpty(t, s1)

a2 := defaultApp(t)
s2 := a2.jwtSecret()
assert.NotEqual(t, s1, s2)
}

func TestApp_NewApp(t *testing.T) {
a := defaultApp(t)
assert.NotNil(t, a.rawLogger)
assert.NotNil(t, a.logger)
assert.IsType(t, slognil.Handler{}, a.logger.Handler())
assert.Equal(t, "test", a.Version.RefName)
}

func TestApp_Configure(t *testing.T) {
a := defaultApp(t)
assert.Nil(t, a.db)
assert.Nil(t, a.translator)
assert.Nil(t, a.humanizer)

t.Setenv("WT_DATABASE_DRIVER", "memory")
require.NoError(t, a.Configure())

assert.Equal(t, "memory", a.Config.DatabaseDriver)
assert.NotNil(t, a.db)
assert.NotNil(t, a.translator)
assert.NotNil(t, a.humanizer)
}

func TestApp_NewLogger(t *testing.T) {
l := newLogger(false)
assert.IsType(t, slognil.Handler{}, l.Handler())

l = newLogger(true)
assert.IsType(t, &slog.JSONHandler{}, l.Handler())
}

func TestApp_RandomJWTErrorIdemPotent(t *testing.T) {
a := defaultApp(t)
s1 := a.jwtSecret()
assert.NotEmpty(t, s1)

s2 := a.jwtSecret()
assert.Equal(t, s1, s2)
}
3 changes: 3 additions & 0 deletions pkg/app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
type Config struct {
Bind string `mapstructure:"bind"`
JWTEncryptionKey string `mapstructure:"jwt_encryption_key"`
Logging bool `mapstructure:"logging"`
Debug bool `mapstructure:"debug"`
DatabaseDriver string `mapstructure:"database_driver"`
DSN string `mapstructure:"dsn"`
Expand All @@ -18,13 +19,15 @@ func (a *App) ReadConfiguration() error {
viper.SetEnvPrefix("WT")

viper.SetDefault("bind", "[::]:8080")
viper.SetDefault("logging", "true")
viper.SetDefault("debug", "false")
viper.SetDefault("database_driver", "sqlite")
viper.SetDefault("dsn", "./database.db")

for _, envVar := range []string{
"bind",
"jwt_encryption_key",
"logging",
"debug",
"database_driver",
"dsn",
Expand Down
35 changes: 32 additions & 3 deletions pkg/app/i18n.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,41 @@ import (
"golang.org/x/text/language"
)

var (
BrowserLanguage = "browser"

const (
BrowserLanguage = "browser"
DefaultTotalsShow = database.WorkoutTypeRunning
)

func (a *App) ConfigureLocalizer() error {
var domain spreak.FsOption

if a.Translations != nil {
domain = spreak.WithFs(a.Translations)
} else {
domain = spreak.WithPath(".")
}

bundle, err := spreak.NewBundle(
// Set the language used in the program code/templates
spreak.WithSourceLanguage(language.English),
// Set the path from which the translations should be loaded
spreak.WithFilesystemLoader(spreak.NoDomain, domain),
// Specify the languages you want to load
spreak.WithLanguage(translations()...),
)
if err != nil {
return err
}

a.translator = bundle

a.humanizer = humanize.MustNew(
humanize.WithLocale(humanLocales()...),
)

return nil
}

func translations() []interface{} {
return []interface{}{
language.English,
Expand Down
5 changes: 4 additions & 1 deletion pkg/app/tempates.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ func (a *App) viewTemplateFunctions() template.FuncMap {

func (a *App) parseViewTemplates() *template.Template {
templ := template.New("").Funcs(a.viewTemplateFunctions())
if a.Views == nil {
return templ
}

err := fs.WalkDir(a.Views, ".", func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
if d != nil && d.IsDir() {
return err
}

Expand Down
Empty file added pkg/app/test_assets/.gitkeep
Empty file.
Empty file.
Empty file added pkg/app/test_views/.gitkeep
Empty file.
2 changes: 1 addition & 1 deletion pkg/database/gorm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestGorm(t *testing.T) {
func TestGorm_Connect(t *testing.T) {
db, err := Connect("memory", "", false, slog.Default())
require.NoError(t, err)
assert.NotNil(t, db)
Expand Down
26 changes: 18 additions & 8 deletions pkg/database/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ func defaultUser() *User {
}
}

func dummyMapData() *MapData {
return dummyMapDataWithName("dummy map data")
}

func dummyMapDataWithName(name string) *MapData {
return &MapData{
Name: name,
}
}

func createMemoryDB(t *testing.T) *gorm.DB {
db, err := Connect("memory", "", false, slognil.NewLogger())
require.NoError(t, err)
Expand All @@ -28,15 +38,15 @@ func createDefaultUser(t *testing.T, db *gorm.DB) {
require.NoError(t, defaultUser().Create(db))
}

func TestUserIsValid(t *testing.T) {
func TestUser_IsValid(t *testing.T) {
u := defaultUser()
u.Active = true

require.NoError(t, u.IsValid())
assert.True(t, u.IsActive())
}

func TestUserPasswordIsValid(t *testing.T) {
func TestUser_PasswordIsValid(t *testing.T) {
pwd := "my-password"
u := defaultUser()
u.Active = true
Expand All @@ -57,7 +67,7 @@ func TestUserPasswordIsValid(t *testing.T) {
assert.False(t, u.ValidLogin(pwd+pwd))
}

func TestUserIsNotActive(t *testing.T) {
func TestUser_IsNotActive(t *testing.T) {
u := User{
Username: "my-username",
Password: "my-password",
Expand All @@ -68,7 +78,7 @@ func TestUserIsNotActive(t *testing.T) {
assert.False(t, u.IsActive())
}

func TestUserUsernameIsEmail(t *testing.T) {
func TestUser_UsernameIsEmail(t *testing.T) {
u := User{
Username: "my-username@localhost",
Password: "my-password",
Expand All @@ -78,7 +88,7 @@ func TestUserUsernameIsEmail(t *testing.T) {
assert.False(t, u.IsActive())
}

func TestUserUsernameIsNotValid(t *testing.T) {
func TestUser_UsernameIsNotValid(t *testing.T) {
for _, username := range []string{
"invalid-char-;",
"invalid-char-@",
Expand All @@ -96,7 +106,7 @@ func TestUserUsernameIsNotValid(t *testing.T) {
}
}

func TestUserUsernameIsTooLong(t *testing.T) {
func TestUser_UsernameIsTooLong(t *testing.T) {
u := User{
Username: "too-long-too-long-too-long-too-long-too-long-too-long-too-long-too-long",
Password: "my-password",
Expand All @@ -106,7 +116,7 @@ func TestUserUsernameIsTooLong(t *testing.T) {
assert.False(t, u.IsActive())
}

func TestUserPasswordNotSet(t *testing.T) {
func TestUser_PasswordNotSet(t *testing.T) {
u := User{
Username: "username",
Password: "",
Expand All @@ -116,7 +126,7 @@ func TestUserPasswordNotSet(t *testing.T) {
assert.False(t, u.IsActive())
}

func TestDatabaseUserBeforeCreateNoPassword(t *testing.T) {
func TestUser_BeforeCreateNoPassword(t *testing.T) {
db := createMemoryDB(t)
u := &User{
Username: "username",
Expand Down
28 changes: 28 additions & 0 deletions pkg/database/workout_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package database

import "slices"

type WorkoutType string

const (
WorkoutTypeAutoDetect WorkoutType = "auto"
WorkoutTypeRunning WorkoutType = "running"
WorkoutTypeCycling WorkoutType = "cycling"
WorkoutTypeWalking WorkoutType = "walking"
)

func WorkoutTypes() []WorkoutType {
return []WorkoutType{WorkoutTypeRunning, WorkoutTypeCycling, WorkoutTypeWalking}
}

func DistanceWorkoutTypes() []WorkoutType {
return []WorkoutType{WorkoutTypeRunning, WorkoutTypeCycling, WorkoutTypeWalking}
}

func (wt WorkoutType) String() string {
return string(wt)
}

func (wt WorkoutType) IsDistance() bool {
return slices.Contains(DistanceWorkoutTypes(), wt)
}
Loading

0 comments on commit 159c7ef

Please sign in to comment.