From 5a595ab9f38d19ff6a8c72f43149fb56fddf6b94 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 28 Aug 2025 11:49:53 -0400 Subject: [PATCH 01/10] replace testify with should --- database/database_test.go | 8 +- database/project_test.go | 15 ++- go.mod | 7 +- go.sum | 2 + projects_test.go | 105 +++++++++++---------- reports_test.go | 44 ++++----- user_test.go | 192 +++++++++++++++++++------------------- 7 files changed, 184 insertions(+), 189 deletions(-) diff --git a/database/database_test.go b/database/database_test.go index 800dfdb..a90bfe4 100644 --- a/database/database_test.go +++ b/database/database_test.go @@ -4,15 +4,15 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" + "github.com/Kairum-Labs/should" ) func TestMain(m *testing.M) { - //main.setLogging() + // main.setLogging() os.Setenv("DB_FILE", "test.db") //nolint:errcheck _ = InitializeDatabase() defer Close() - //main.checkDefaultUser() + // main.checkDefaultUser() os.Exit(m.Run()) } @@ -23,6 +23,6 @@ func TestCloseDB(t *testing.T) { t.Run("closed", func(t *testing.T) { Close() err := InitializeDatabase() - assert.Nil(t, err) + should.BeNil(t, err) }) } diff --git a/database/project_test.go b/database/project_test.go index 39ac04a..5cff0a5 100644 --- a/database/project_test.go +++ b/database/project_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" + "github.com/Kairum-Labs/should" "github.com/devilcove/timetraced/models" "github.com/google/uuid" - "github.com/stretchr/testify/assert" ) func TestSaveProject(t *testing.T) { @@ -16,7 +16,7 @@ func TestSaveProject(t *testing.T) { Active: true, } err := SaveProject(&p) - assert.Nil(t, err) + should.BeNil(t, err) } func TestGetProject(t *testing.T) { @@ -26,16 +26,15 @@ func TestGetProject(t *testing.T) { Active: true, Updated: time.Now(), }) - assert.Nil(t, err) + should.BeNil(t, err) t.Run("exists", func(t *testing.T) { project, err := GetProject("test") - assert.Nil(t, err) - assert.Equal(t, "test", project.Name) + should.BeNil(t, err) + should.BeEqual(t, project.Name, "test") }) t.Run("missing", func(t *testing.T) { project, err := GetProject("test2") - assert.NotNil(t, err) - assert.Equal(t, models.Project{}, project) + should.NotBeNil(t, err) + should.BeEqual(t, project, models.Project{}) }) - } diff --git a/go.mod b/go.mod index 10c55f0..5c2d057 100644 --- a/go.mod +++ b/go.mod @@ -2,14 +2,12 @@ module github.com/devilcove/timetraced go 1.23.0 -toolchain go1.24.1 - require ( + github.com/Kairum-Labs/should v0.1.0 github.com/gin-contrib/sessions v1.0.4 github.com/gin-gonic/gin v1.10.1 github.com/google/uuid v1.6.0 github.com/joho/godotenv v1.5.1 - github.com/stretchr/testify v1.11.0 go.etcd.io/bbolt v1.4.3 golang.org/x/crypto v0.41.0 ) @@ -20,7 +18,6 @@ require ( github.com/bytedance/sonic v1.13.2 // indirect github.com/bytedance/sonic/loader v0.2.4 // indirect github.com/cloudwego/base64x v0.1.5 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gin-contrib/sse v1.0.0 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -38,7 +35,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.11.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.16.0 // indirect diff --git a/go.sum b/go.sum index b5c96c2..9a5ac74 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Kairum-Labs/should v0.1.0 h1:7CpOfhWX7yIwMbUwUdCmtKC/UJaNt2YyKbFn8dvMrdk= +github.com/Kairum-Labs/should v0.1.0/go.mod h1:vP/ASEjUAKoWy/M7uIrAXq69p7/IUWOpEe5R+q/+K34= github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= diff --git a/projects_test.go b/projects_test.go index c26ccc0..a4edf02 100644 --- a/projects_test.go +++ b/projects_test.go @@ -9,186 +9,185 @@ import ( "testing" "time" + "github.com/Kairum-Labs/should" "github.com/devilcove/timetraced/database" "github.com/devilcove/timetraced/models" "github.com/google/uuid" - "github.com/stretchr/testify/assert" ) func TestAddProject(t *testing.T) { deleteAllProjects() err := createTestUser(models.User{Username: "admin", Password: "password", IsAdmin: true}) - assert.Nil(t, err) + should.BeNil(t, err) t.Run("new project", func(t *testing.T) { cookie := testLogin(models.User{Username: "admin", Password: "password"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() project := models.Project{ Name: "test", } payload, err := json.Marshal(&project) - assert.Nil(t, err) + should.BeNil(t, err) t.Log(string(payload)) req, err := http.NewRequest(http.MethodPost, "/projects", bytes.NewBuffer(payload)) - assert.Nil(t, err) + should.BeNil(t, err) req.AddCookie(cookie) req.Header.Set("Content-Type", "application/json") b, err := io.ReadAll(req.Body) - assert.Nil(t, err) + should.BeNil(t, err) t.Log(string(b)) router.ServeHTTP(w, req) - assert.Equal(t, http.StatusBadRequest, w.Code) + should.BeEqual(t, w.Code, http.StatusBadRequest) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) + should.BeNil(t, err) t.Log(string(body)) - assert.Contains(t, string(body), "") + should.ContainSubstring(t, string(body), "") }) t.Run("invalid data", func(t *testing.T) { cookie := testLogin(models.User{Username: "admin", Password: "password"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodPost, "/projects", nil) req.AddCookie(cookie) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) - assert.Equal(t, http.StatusBadRequest, w.Code) + should.BeEqual(t, w.Code, http.StatusBadRequest) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Contains(t, string(body), "could not decode request") + should.BeNil(t, err) + should.ContainSubstring(t, string(body), "could not decode request") }) t.Run("invalid data2", func(t *testing.T) { cookie := testLogin(models.User{Username: "admin", Password: "password"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() payload, err := json.Marshal(models.Project{ Name: "test name", }) - assert.Nil(t, err) + should.BeNil(t, err) req, _ := http.NewRequest(http.MethodPost, "/projects", bytes.NewBuffer(payload)) req.AddCookie(cookie) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) - assert.Equal(t, http.StatusBadRequest, w.Code) + should.BeEqual(t, w.Code, http.StatusBadRequest) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Contains(t, string(body), "invalid project name") + should.BeNil(t, err) + should.ContainSubstring(t, string(body), "invalid project name") }) t.Run("project exists", func(t *testing.T) { createTestProjects() cookie := testLogin(models.User{Username: "admin", Password: "password"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() payload, err := json.Marshal(models.Project{ Name: "test", }) - assert.Nil(t, err) + should.BeNil(t, err) req, _ := http.NewRequest(http.MethodPost, "/projects", bytes.NewBuffer(payload)) req.AddCookie(cookie) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) - assert.Equal(t, http.StatusBadRequest, w.Code) + should.BeEqual(t, w.Code, http.StatusBadRequest) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Contains(t, string(body), "project exists") + should.BeNil(t, err) + should.ContainSubstring(t, string(body), "project exists") }) - } func TestGetProjects(t *testing.T) { deleteAllProjects() createTestProjects() err := createTestUser(models.User{Username: "test", Password: "test", IsAdmin: false}) - assert.Nil(t, err) + should.BeNil(t, err) t.Run("existing project", func(t *testing.T) { cookie := testLogin(models.User{Username: "test", Password: "test"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodGet, "/projects/test", nil) req.AddCookie(cookie) router.ServeHTTP(w, req) - assert.Equal(t, http.StatusOK, w.Code) + should.BeEqual(t, w.Code, http.StatusOK) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) + should.BeNil(t, err) msg := models.Project{} err = json.Unmarshal(body, &msg) - assert.Nil(t, err) - assert.Equal(t, "test", msg.Name) + should.BeNil(t, err) + should.BeEqual(t, msg.Name, "test") }) t.Run("wrong project", func(t *testing.T) { cookie := testLogin(models.User{Username: "admin", Password: "password"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodGet, "/projects/missing", nil) req.AddCookie(cookie) router.ServeHTTP(w, req) - assert.Equal(t, http.StatusBadRequest, w.Code) + should.BeEqual(t, w.Code, http.StatusBadRequest) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Contains(t, string(body), "could not retrieve project no such project") + should.BeNil(t, err) + should.ContainSubstring(t, string(body), "could not retrieve project no such project") }) t.Run("get all", func(t *testing.T) { cookie := testLogin(models.User{Username: "admin", Password: "password"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodGet, "/projects", nil) req.AddCookie(cookie) router.ServeHTTP(w, req) - assert.Equal(t, http.StatusOK, w.Code) + should.BeEqual(t, w.Code, http.StatusOK) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) + should.BeNil(t, err) msg := []models.Project{} err = json.Unmarshal(body, &msg) - assert.Nil(t, err) - assert.Equal(t, 5, len(msg)) + should.BeNil(t, err) + should.BeEqual(t, len(msg), 5) }) t.Run("get all when empty", func(t *testing.T) { deleteAllProjects() cookie := testLogin(models.User{Username: "admin", Password: "password"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodGet, "/projects", nil) req.AddCookie(cookie) router.ServeHTTP(w, req) - assert.Equal(t, http.StatusOK, w.Code) + should.BeEqual(t, w.Code, http.StatusOK) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) + should.BeNil(t, err) msg := []models.StatusResponse{} err = json.Unmarshal(body, &msg) - assert.Nil(t, err) - assert.Equal(t, 0, len(msg)) + should.BeNil(t, err) + should.BeEqual(t, len(msg), 0) }) } func TestGetStatus(t *testing.T) { createTestRecords() err := createTestUser(models.User{Username: "test", Password: "test", IsAdmin: false}) - assert.Nil(t, err) + should.BeNil(t, err) cookie := testLogin(models.User{Username: "test", Password: "test"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodGet, "/projects/status", nil) req.AddCookie(cookie) router.ServeHTTP(w, req) - assert.Equal(t, http.StatusOK, w.Code) + should.BeEqual(t, w.Code, http.StatusOK) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Contains(t, string(body), "Current Project: ") + should.BeNil(t, err) + should.ContainSubstring(t, string(body), "Current Project: ") } func TestStartStopProject(t *testing.T) { @@ -196,16 +195,16 @@ func TestStartStopProject(t *testing.T) { createTestProjects() t.Run("non-existent Project", func(t *testing.T) { cookie := testLogin(models.User{Username: "admin", Password: "password"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodPost, "/projects/junk/start", nil) req.AddCookie(cookie) router.ServeHTTP(w, req) - assert.Equal(t, http.StatusInternalServerError, w.Code) + should.BeEqual(t, w.Code, http.StatusInternalServerError) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Contains(t, string(body), "no such project") + should.BeNil(t, err) + should.ContainSubstring(t, string(body), "no such project") }) } diff --git a/reports_test.go b/reports_test.go index 77dd843..a6a3f4f 100644 --- a/reports_test.go +++ b/reports_test.go @@ -6,35 +6,34 @@ import ( "io" "net/http" "net/http/httptest" + "strings" "testing" "time" + "github.com/Kairum-Labs/should" "github.com/devilcove/timetraced/database" "github.com/devilcove/timetraced/models" "github.com/google/uuid" - "github.com/stretchr/testify/assert" ) func TestGetReport(t *testing.T) { deleteAllUsers() deleteAllRecords() err := createTestUser(models.User{Username: "test", Password: "testing"}) - assert.Nil(t, err) + should.BeNil(t, err) cookie := testLogin(models.User{Username: "test", Password: "testing"}) - assert.NotNil(t, cookie) + should.NotBeNil(t, cookie) t.Run("no request", func(t *testing.T) { - w := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodPost, "/reports", nil) req.AddCookie(cookie) router.ServeHTTP(w, req) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Equal(t, http.StatusBadRequest, w.Code) - assert.Contains(t, string(body), "could not decode request") + should.BeNil(t, err) + should.BeEqual(t, w.Code, http.StatusBadRequest) + should.ContainSubstring(t, string(body), "could not decode request") }) t.Run("no records", func(t *testing.T) { - w := httptest.NewRecorder() request := models.ReportRequest{ Start: time.Now().Add(-24 * time.Hour).Format("2006-01-02"), @@ -42,20 +41,22 @@ func TestGetReport(t *testing.T) { Project: "nilProject", } payload, err := json.Marshal(&request) - assert.Nil(t, err) + should.BeNil(t, err) req, _ := http.NewRequest(http.MethodPost, "/reports", bytes.NewBuffer(payload)) req.AddCookie(cookie) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Equal(t, http.StatusOK, w.Code) - assert.NotContains(t, string(body), "") + should.BeNil(t, err) + should.BeEqual(t, w.Code, http.StatusOK) + // should.NotContainSubstring(t, string(body), "") + if strings.Contains(string(body), "") { + t.Fail() + } }) t.Run("one user/one project", func(t *testing.T) { createTestRecords() - w := httptest.NewRecorder() data := models.ReportRequest{ Start: time.Now().Add(-24 * time.Hour).Format("2006-01-02"), @@ -63,15 +64,15 @@ func TestGetReport(t *testing.T) { Project: "timetrace", } payload, err := json.Marshal(data) - assert.Nil(t, err) + should.BeNil(t, err) req, _ := http.NewRequest(http.MethodPost, "/reports", bytes.NewBuffer(payload)) req.AddCookie(cookie) req.Header.Set("Content-Type", "application/json") router.ServeHTTP(w, req) body, _ := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Equal(t, http.StatusOK, w.Code) - assert.Contains(t, string(body), "

Project timetrace") + should.BeNil(t, err) + should.BeEqual(t, w.Code, http.StatusOK) + should.ContainSubstring(t, string(body), "

Project timetrace") }) t.Run("all records", func(t *testing.T) { @@ -85,17 +86,16 @@ func TestGetReport(t *testing.T) { Project: "", } payload, err := json.Marshal(data) - assert.Nil(t, err) + should.BeNil(t, err) req, _ := http.NewRequest(http.MethodPost, "/reports", bytes.NewBuffer(payload)) req.Header.Set("Content-Type", "application/json") req.AddCookie(cookie) router.ServeHTTP(w, req) body, err := io.ReadAll(w.Result().Body) - assert.Nil(t, err) - assert.Equal(t, http.StatusOK, w.Code) - assert.Contains(t, string(body), " + diff --git a/html/configuration.html b/html/configuration.html index 3e52c81..6128c1c 100644 --- a/html/configuration.html +++ b/html/configuration.html @@ -3,7 +3,7 @@

Configuration

-
+


-
-
- -

- -
+
+

Timetrace Login

+ +
+
+
+
+
+

+ +
+
+ {{end}} \ No newline at end of file diff --git a/html/navbar.html b/html/navbar.html index ca72e7e..cb857cd 100644 --- a/html/navbar.html +++ b/html/navbar.html @@ -11,17 +11,14 @@ Projects
{{range .Projects }} -
{{end}}
-
-
+ +
- Logout + Logout - - -

+
+

+ +

diff --git a/html/register.html b/html/register.html index 1541e7a..5a39843 100644 --- a/html/register.html +++ b/html/register.html @@ -1,17 +1,20 @@ {{define "register"}} -
-
-

Timetrace Registration

-
-
-
-
-
- -
- +
+
+

Timetrace Add User

+
+
+
+
+
+
+
+

+ +
+
+ Cancel
+
{{end}} \ No newline at end of file diff --git a/html/report.html b/html/report.html index 6cb484d..d65cbcd 100644 --- a/html/report.html +++ b/html/report.html @@ -3,7 +3,7 @@

Reports

-
+

@@ -38,7 +38,8 @@

Project {{.Project}}

{{end}}

{{.Total}}

{{end}} - +
{{end}} diff --git a/html/user.html b/html/user.html index f9756da..c3a77e8 100644 --- a/html/user.html +++ b/html/user.html @@ -16,10 +16,14 @@

Users

{{.Username}} {{.IsAdmin}} - + {{end}} +
+

New User  

+
{{end}} @@ -29,18 +33,24 @@

Users


Edit User

-

{{.Username}}

+

{{.Username}} {{.IsAdmin}}

-
+


+ {{ if .AsAdmin }} + +

+ + {{else}} + {{end }}