Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fluent Testing API #31

Merged
merged 2 commits into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 89 additions & 91 deletions backend/tests/api/category_test.go
Original file line number Diff line number Diff line change
@@ -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()
}
11 changes: 6 additions & 5 deletions backend/tests/api/health_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
}
117 changes: 97 additions & 20 deletions backend/tests/api/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
crand "crypto/rand"
"fmt"
"io"
"math/big"
"net"
"net/http"
Expand Down Expand Up @@ -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)
}
}
Expand All @@ -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) {
Expand Down
Loading
Loading