diff --git a/backend/tests/api/category_test.go b/backend/tests/api/category_test.go index 173aed0b9..4119dc3cb 100644 --- a/backend/tests/api/category_test.go +++ b/backend/tests/api/category_test.go @@ -1,127 +1,125 @@ package tests import ( - "io" + "fmt" + "net/http" "testing" "github.com/GenerateNU/sac/backend/src/models" "github.com/GenerateNU/sac/backend/src/transactions" + "github.com/huandu/go-assert" "github.com/goccy/go-json" ) -func TestCreateCategoryWorks(t *testing.T) { - app, assert, resp := RequestTesterWithJSONBody(t, "POST", "/api/v1/categories/", &map[string]interface{}{ - "category_name": "Science", - }, nil, nil, nil) - defer app.DropDB() +func CreateSampleCategory(t *testing.T, categoryName string) ExistingAppAssert { + return TestRequest{ + Method: "POST", + Path: "/api/v1/categories/", + Body: &map[string]interface{}{ + "category_name": categoryName, + }, + }.TestOnStatusAndDBKeepDB(t, nil, + DBTesterWithStatus{ + Status: 201, + DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - assert.Equal(201, resp.StatusCode) + var respCategory models.Category - var respCategory models.Category + err := json.NewDecoder(resp.Body).Decode(&respCategory) - err := json.NewDecoder(resp.Body).Decode(&respCategory) + assert.NilError(err) - assert.NilError(err) + dbCategory, err := transactions.GetCategory(app.Conn, respCategory.ID) - dbCategory, err := transactions.GetCategory(app.Conn, respCategory.ID) + assert.NilError(err) - assert.NilError(err) + assert.Equal(dbCategory, &respCategory) + }, + }, + ) +} - assert.Equal(dbCategory, &respCategory) +func TestCreateCategoryWorks(t *testing.T) { + appAssert := CreateSampleCategory(t, "Science") + appAssert.App.DropDB() } func TestCreateCategoryIgnoresid(t *testing.T) { - app, assert, resp := RequestTesterWithJSONBody(t, "POST", "/api/v1/categories/", &map[string]interface{}{ - "id": 12, - "category_name": "Science", - }, nil, nil, nil) - defer app.DropDB() - - var respCategory models.Category - - err := json.NewDecoder(resp.Body).Decode(&respCategory) - - assert.NilError(err) - - dbCategory, err := transactions.GetCategory(app.Conn, respCategory.ID) - - assert.NilError(err) - - assert.NotEqual(12, dbCategory.ID) + TestRequest{ + Method: "POST", + Path: "/api/v1/categories/", + Body: &map[string]interface{}{ + "id": 12, + "category_name": "Science", + }, + }.TestOnStatusAndDB(t, nil, + DBTesterWithStatus{ + Status: 201, + DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { + var respCategory models.Category + + err := json.NewDecoder(resp.Body).Decode(&respCategory) + + assert.NilError(err) + + dbCategory, err := transactions.GetCategory(app.Conn, respCategory.ID) + + assert.NilError(err) + + assert.NotEqual(12, dbCategory.ID) + }, + }, + ) } func TestCreateCategoryFailsIfNameIsNotString(t *testing.T) { - app, assert, resp := RequestTesterWithJSONBody(t, "POST", "/api/v1/categories/", &map[string]interface{}{ - "category_name": 1231, - }, nil, nil, nil) - defer app.DropDB() - - defer resp.Body.Close() - - bodyBytes, err := io.ReadAll(resp.Body) - - assert.NilError(err) - - msg := string(bodyBytes) - - assert.Equal("failed to process the request", msg) - - assert.Equal(400, resp.StatusCode) + TestRequest{ + Method: "POST", + Path: "/api/v1/categories/", + Body: &map[string]interface{}{ + "category_name": 1231, + }, + }.TestOnStatusAndMessage(t, nil, + MessageWithStatus{ + Status: 400, + Message: "failed to process the request", + }) } func TestCreateCategoryFailsIfNameIsMissing(t *testing.T) { - app, assert, resp := RequestTesterWithJSONBody(t, "POST", "/api/v1/categories/", &map[string]interface{}{}, nil, nil, nil) - defer app.DropDB() - - defer resp.Body.Close() - - bodyBytes, err := io.ReadAll(resp.Body) - - assert.NilError(err) - - msg := string(bodyBytes) - - assert.Equal("failed to validate the data", msg) - - assert.Equal(400, resp.StatusCode) + TestRequest{ + Method: "POST", + Path: "/api/v1/categories/", + Body: &map[string]interface{}{}, + }.TestOnStatusAndMessage(t, nil, + MessageWithStatus{ + Status: 400, + Message: "failed to validate the data", + }, + ) } func TestCreateCategoryFailsIfCategoryWithThatNameAlreadyExists(t *testing.T) { categoryName := "Science" - app, assert, resp := RequestTesterWithJSONBody(t, "POST", "/api/v1/categories/", &map[string]interface{}{ - "category_name": categoryName, - }, nil, nil, nil) - - assert.Equal(201, resp.StatusCode) - - var respCategory models.Category - - err := json.NewDecoder(resp.Body).Decode(&respCategory) - - assert.NilError(err) - - dbCategory, err := transactions.GetCategory(app.Conn, respCategory.ID) - assert.NilError(err) - - assert.Equal(dbCategory, &respCategory) + existingAppAssert := CreateSampleCategory(t, categoryName) for _, permutation := range AllCasingPermutations(categoryName) { - _, _, resp = RequestTesterWithJSONBody(t, "POST", "/api/v1/categories/", &map[string]interface{}{ - "category_name": permutation, - }, nil, &app, assert) - - defer resp.Body.Close() - - bodyBytes, err := io.ReadAll(resp.Body) - - assert.NilError(err) - - msg := string(bodyBytes) - - assert.Equal("category with that name already exists", msg) - - assert.Equal(400, resp.StatusCode) + fmt.Println(permutation) + TestRequest{ + Method: "POST", + Path: "/api/v1/categories/", + Body: &map[string]interface{}{ + "category_name": permutation, + }, + }.TestOnStatusAndMessageKeepDB(t, &existingAppAssert, + MessageWithStatus{ + Status: 400, + Message: "category with that name already exists", + }, + ) } + + existingAppAssert.App.DropDB() } diff --git a/backend/tests/api/health_test.go b/backend/tests/api/health_test.go index 1c86da726..a44d19d2c 100644 --- a/backend/tests/api/health_test.go +++ b/backend/tests/api/health_test.go @@ -5,9 +5,10 @@ import ( ) func TestHealthWorks(t *testing.T) { - app, assert, resp := RequestTester(t, "GET", "/health", nil, nil, nil, nil) - - defer app.DropDB() - - assert.Equal(200, resp.StatusCode) + TestRequest{ + Method: "GET", + Path: "/health", + }.TestOnStatus(t, nil, + 200, + ) } diff --git a/backend/tests/api/helpers.go b/backend/tests/api/helpers.go index 6891a1b27..534f00f4e 100644 --- a/backend/tests/api/helpers.go +++ b/backend/tests/api/helpers.go @@ -4,6 +4,7 @@ import ( "bytes" crand "crypto/rand" "fmt" + "io" "math/big" "net" "net/http" @@ -133,37 +134,43 @@ func (app TestApp) DropDB() { app.Conn.Exec(fmt.Sprintf("DROP DATABASE %s;", app.Settings.Database.DatabaseName)) } +type ExistingAppAssert struct { + App TestApp + Assert *assert.A +} + type TestRequest struct { - TestApp TestApp - Assert *assert.A - Resp *http.Response + Method string + Path string + Body *map[string]interface{} + Headers *map[string]string } -func RequestTester(t *testing.T, method string, path string, body *map[string]interface{}, headers *map[string]string, exisitingApp *TestApp, exisitingAssert *assert.A) (TestApp, *assert.A, *http.Response) { +func (request TestRequest) Test(t *testing.T, existingAppAssert *ExistingAppAssert) (ExistingAppAssert, *http.Response) { var app TestApp var assert *assert.A - if exisitingApp == nil || exisitingAssert == nil { + if existingAppAssert == nil { app, assert = InitTest(t) } else { - app, assert = *exisitingApp, exisitingAssert + app, assert = existingAppAssert.App, existingAppAssert.Assert } - address := fmt.Sprintf("%s%s", app.Address, path) + address := fmt.Sprintf("%s%s", app.Address, request.Path) var req *http.Request - if body == nil { - req = httptest.NewRequest(method, address, nil) + if request.Body == nil { + req = httptest.NewRequest(request.Method, address, nil) } else { - bodyBytes, err := json.Marshal(body) + bodyBytes, err := json.Marshal(request.Body) assert.NilError(err) - req = httptest.NewRequest(method, address, bytes.NewBuffer(bodyBytes)) + req = httptest.NewRequest(request.Method, address, bytes.NewBuffer(bodyBytes)) - if headers != nil { - for key, value := range *headers { + if request.Headers != nil { + for key, value := range *request.Headers { req.Header.Set(key, value) } } @@ -173,17 +180,87 @@ func RequestTester(t *testing.T, method string, path string, body *map[string]in assert.NilError(err) - return app, assert, resp + return ExistingAppAssert{ + App: app, + Assert: assert, + }, resp +} + +func (request TestRequest) TestOnStatus(t *testing.T, existingAppAssert *ExistingAppAssert, status int) ExistingAppAssert { + appAssert, resp := request.Test(t, existingAppAssert) + app, assert := appAssert.App, appAssert.Assert + if existingAppAssert != nil { + defer app.DropDB() + } + + assert.Equal(status, resp.StatusCode) + + return appAssert } -func RequestTesterWithJSONBody(t *testing.T, method string, path string, body *map[string]interface{}, headers *map[string]string, exisitingApp *TestApp, exisitingAssert *assert.A) (TestApp, *assert.A, *http.Response) { - if headers == nil { - headers = &map[string]string{"Content-Type": "application/json"} - } else if _, ok := (*headers)["Content-Type"]; !ok { - (*headers)["Content-Type"] = "application/json" +func (request TestRequest) TestWithJSONBody(t *testing.T, existingAppAssert *ExistingAppAssert) (ExistingAppAssert, *http.Response) { + if request.Headers == nil { + request.Headers = &map[string]string{"Content-Type": "application/json"} + } else if _, ok := (*request.Headers)["Content-Type"]; !ok { + (*request.Headers)["Content-Type"] = "application/json" } - return RequestTester(t, method, path, body, headers, exisitingApp, exisitingAssert) + return request.Test(t, existingAppAssert) +} + +type MessageWithStatus struct { + Status int + Message string +} + +func (request TestRequest) TestOnStatusAndMessage(t *testing.T, existingAppAssert *ExistingAppAssert, messagedStatus MessageWithStatus) ExistingAppAssert { + appAssert := request.TestOnStatusAndMessageKeepDB(t, existingAppAssert, messagedStatus) + appAssert.App.DropDB() + return appAssert +} + +func (request TestRequest) TestOnStatusAndMessageKeepDB(t *testing.T, existingAppAssert *ExistingAppAssert, messagedStatus MessageWithStatus) ExistingAppAssert { + appAssert, resp := request.TestWithJSONBody(t, existingAppAssert) + assert := appAssert.Assert + + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + + appAssert.Assert.NilError(err) + + msg := string(bodyBytes) + + assert.Equal(messagedStatus.Message, msg) + + assert.Equal(messagedStatus.Status, resp.StatusCode) + + return appAssert +} + +type DBTester func(app TestApp, assert *assert.A, resp *http.Response) + +type DBTesterWithStatus struct { + Status int + DBTester +} + +func (request TestRequest) TestOnStatusAndDB(t *testing.T, existingAppAssert *ExistingAppAssert, dbTesterStatus DBTesterWithStatus) ExistingAppAssert { + appAssert := request.TestOnStatusAndDBKeepDB(t, existingAppAssert, dbTesterStatus) + appAssert.App.DropDB() + return appAssert +} + +func (request TestRequest) TestOnStatusAndDBKeepDB(t *testing.T, existingAppAssert *ExistingAppAssert, dbTesterStatus DBTesterWithStatus) ExistingAppAssert { + appAssert, resp := request.TestWithJSONBody(t, existingAppAssert) + app, assert := appAssert.App, appAssert.Assert + defer resp.Body.Close() + + assert.Equal(dbTesterStatus.Status, resp.StatusCode) + + dbTesterStatus.DBTester(app, assert, resp) + + return appAssert } func generateCasingPermutations(word string, currentPermutation string, index int, results *[]string) { diff --git a/backend/tests/api/user_test.go b/backend/tests/api/user_test.go index a0d73cdd4..8307c0dc9 100644 --- a/backend/tests/api/user_test.go +++ b/backend/tests/api/user_test.go @@ -1,41 +1,47 @@ package tests import ( + "net/http" "testing" "github.com/GenerateNU/sac/backend/src/models" "github.com/GenerateNU/sac/backend/src/transactions" + "github.com/huandu/go-assert" "github.com/goccy/go-json" ) func TestGetAllUsersWorks(t *testing.T) { - // setup the test - app, assert, resp := RequestTester(t, "GET", "/api/v1/users/", nil, nil, nil, nil) - defer app.DropDB() + TestRequest{ + Method: "GET", + Path: "/api/v1/users/", + }.TestOnStatusAndDB(t, nil, + DBTesterWithStatus{ + Status: 200, + DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { + // decode the response body into a slice of users + var users []models.User - assert.Equal(200, resp.StatusCode) + err := json.NewDecoder(resp.Body).Decode(&users) - // decode the response body into a slice of users - var users []models.User + assert.NilError(err) - err := json.NewDecoder(resp.Body).Decode(&users) + assert.Equal(1, len(users)) - assert.NilError(err) + respUser := users[0] - assert.Equal(1, len(users)) + // get all users from the database + dbUsers, err := transactions.GetAllUsers(app.Conn) - respUser := users[0] + assert.NilError(err) - // get all users from the database - dbUsers, err := transactions.GetAllUsers(app.Conn) + assert.Equal(1, len(dbUsers)) - assert.NilError(err) + dbUser := dbUsers[0] - assert.Equal(1, len(dbUsers)) - - dbUser := dbUsers[0] - - // assert that the user returned from the database is the same as the user returned from the API - assert.Equal(dbUser, respUser) + // assert that the user returned from the database is the same as the user returned from the API + assert.Equal(dbUser, respUser) + }, + }, + ) }