From 53de437b1e17519147c451304a787cf1f3021663 Mon Sep 17 00:00:00 2001 From: Daniel Giurgiu Date: Thu, 3 Oct 2024 20:13:54 +0300 Subject: [PATCH] Add Unit Tests for DeleteBook Handler --- api/coverage.out | 32 +++--- api/main_test.go | 246 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 16 deletions(-) diff --git a/api/coverage.out b/api/coverage.out index b2642ae..20d00cf 100644 --- a/api/coverage.out +++ b/api/coverage.out @@ -315,22 +315,22 @@ mymodule/main.go:1186.16,1189.3 2 1 mymodule/main.go:1191.2,1191.65 1 1 mymodule/main.go:1191.65,1194.3 2 1 mymodule/main.go:1196.2,1196.48 1 1 -mymodule/main.go:1200.68,1201.35 1 0 -mymodule/main.go:1201.35,1204.3 2 0 -mymodule/main.go:1206.2,1207.16 2 0 -mymodule/main.go:1207.16,1210.3 2 0 -mymodule/main.go:1212.2,1214.16 3 0 -mymodule/main.go:1214.16,1218.3 3 0 -mymodule/main.go:1220.2,1222.16 3 0 -mymodule/main.go:1222.16,1226.3 3 0 -mymodule/main.go:1228.2,1229.16 2 0 -mymodule/main.go:1229.16,1233.3 3 0 -mymodule/main.go:1235.2,1236.23 2 0 -mymodule/main.go:1236.23,1239.3 2 0 -mymodule/main.go:1241.2,1241.24 1 0 -mymodule/main.go:1241.24,1243.17 2 0 -mymodule/main.go:1243.17,1247.4 3 0 -mymodule/main.go:1250.2,1250.46 1 0 +mymodule/main.go:1200.68,1201.35 1 1 +mymodule/main.go:1201.35,1204.3 2 1 +mymodule/main.go:1206.2,1207.16 2 1 +mymodule/main.go:1207.16,1210.3 2 1 +mymodule/main.go:1212.2,1214.16 3 1 +mymodule/main.go:1214.16,1218.3 3 1 +mymodule/main.go:1220.2,1222.16 3 1 +mymodule/main.go:1222.16,1226.3 3 1 +mymodule/main.go:1228.2,1229.16 2 1 +mymodule/main.go:1229.16,1233.3 3 1 +mymodule/main.go:1235.2,1236.23 2 1 +mymodule/main.go:1236.23,1239.3 2 1 +mymodule/main.go:1241.2,1241.24 1 1 +mymodule/main.go:1241.24,1243.17 2 1 +mymodule/main.go:1243.17,1247.4 3 1 +mymodule/main.go:1250.2,1250.46 1 1 mymodule/main.go:1254.74,1255.35 1 0 mymodule/main.go:1255.35,1258.3 2 0 mymodule/main.go:1260.2,1261.16 2 0 diff --git a/api/main_test.go b/api/main_test.go index 6d00047..6c6d103 100644 --- a/api/main_test.go +++ b/api/main_test.go @@ -3600,6 +3600,252 @@ func TestDeleteAuthor_MethodNotAllowed(t *testing.T) { assert.Contains(t, rr.Body.String(), "Only DELETE method is supported") } +// Tests for DeleteBook handler +func TestDeleteBook_Success(t *testing.T) { + app, mock := createTestApp(t) + defer app.DB.Close() + + req := httptest.NewRequest("DELETE", "/books/1", nil) + vars := map[string]string{"id": "1"} + req = mux.SetURLVars(req, vars) + rr := httptest.NewRecorder() + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT author_id FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnRows(sqlmock.NewRows([]string{"author_id"}).AddRow(1)) + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM books WHERE author_id = ? AND id != ?`)). + WithArgs(1, 1). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) + + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + handler := http.HandlerFunc(app.DeleteBook) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + assert.Contains(t, rr.Body.String(), "Book deleted successfully") + + err := mock.ExpectationsWereMet() + assert.NoError(t, err) +} + +func TestDeleteBook_InvalidBookID(t *testing.T) { + app, _ := createTestApp(t) + defer app.DB.Close() + + req := httptest.NewRequest("DELETE", "/books/invalid", nil) + vars := map[string]string{"id": "invalid"} + req = mux.SetURLVars(req, vars) + rr := httptest.NewRecorder() + + handler := http.HandlerFunc(app.DeleteBook) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + assert.Contains(t, rr.Body.String(), "Invalid book ID") +} + +func TestDeleteBook_DBErrorRetrievingAuthorID(t *testing.T) { + app, mock := createTestApp(t) + defer app.DB.Close() + + req := httptest.NewRequest("DELETE", "/books/1", nil) + vars := map[string]string{"id": "1"} + req = mux.SetURLVars(req, vars) + rr := httptest.NewRecorder() + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT author_id FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnError(fmt.Errorf("DB error")) + + handler := http.HandlerFunc(app.DeleteBook) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusInternalServerError, rr.Code) + assert.Contains(t, rr.Body.String(), "Failed to retrieve author ID") + + err := mock.ExpectationsWereMet() + assert.NoError(t, err) +} + +func TestDeleteBook_DBErrorCheckingOtherBooks(t *testing.T) { + app, mock := createTestApp(t) + defer app.DB.Close() + + req := httptest.NewRequest("DELETE", "/books/1", nil) + vars := map[string]string{"id": "1"} + req = mux.SetURLVars(req, vars) + rr := httptest.NewRecorder() + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT author_id FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnRows(sqlmock.NewRows([]string{"author_id"}).AddRow(1)) + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM books WHERE author_id = ? AND id != ?`)). + WithArgs(1, 1). + WillReturnError(fmt.Errorf("DB error")) + + handler := http.HandlerFunc(app.DeleteBook) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusInternalServerError, rr.Code) + assert.Contains(t, rr.Body.String(), "Failed to check for other books") + + err := mock.ExpectationsWereMet() + assert.NoError(t, err) +} + +func TestDeleteBook_NotFound(t *testing.T) { + app, mock := createTestApp(t) + defer app.DB.Close() + + req := httptest.NewRequest("DELETE", "/books/1", nil) + vars := map[string]string{"id": "1"} + req = mux.SetURLVars(req, vars) + rr := httptest.NewRecorder() + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT author_id FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnRows(sqlmock.NewRows([]string{"author_id"}).AddRow(1)) + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM books WHERE author_id = ? AND id != ?`)). + WithArgs(1, 1). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) + + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 0)) + + handler := http.HandlerFunc(app.DeleteBook) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusNotFound, rr.Code) + assert.Contains(t, rr.Body.String(), "Book not found") + + err := mock.ExpectationsWereMet() + assert.NoError(t, err) +} + +func TestDeleteBook_DBErrorDeletingBook(t *testing.T) { + app, mock := createTestApp(t) + defer app.DB.Close() + + req := httptest.NewRequest("DELETE", "/books/1", nil) + vars := map[string]string{"id": "1"} + req = mux.SetURLVars(req, vars) + rr := httptest.NewRecorder() + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT author_id FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnRows(sqlmock.NewRows([]string{"author_id"}).AddRow(1)) + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM books WHERE author_id = ? AND id != ?`)). + WithArgs(1, 1). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) + + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnError(fmt.Errorf("DB error")) + + handler := http.HandlerFunc(app.DeleteBook) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusInternalServerError, rr.Code) + assert.Contains(t, rr.Body.String(), "Failed to delete book") + + err := mock.ExpectationsWereMet() + assert.NoError(t, err) +} + +func TestDeleteBook_DeleteAuthorWhenNoOtherBooks(t *testing.T) { + app, mock := createTestApp(t) + defer app.DB.Close() + + req := httptest.NewRequest("DELETE", "/books/1", nil) + vars := map[string]string{"id": "1"} + req = mux.SetURLVars(req, vars) + rr := httptest.NewRecorder() + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT author_id FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnRows(sqlmock.NewRows([]string{"author_id"}).AddRow(1)) + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM books WHERE author_id = ? AND id != ?`)). + WithArgs(1, 1). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) + + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM authors WHERE id = ?`)). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + handler := http.HandlerFunc(app.DeleteBook) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + assert.Contains(t, rr.Body.String(), "Book deleted successfully") + + err := mock.ExpectationsWereMet() + assert.NoError(t, err) +} + +func TestDeleteBook_MethodNotAllowed(t *testing.T) { + app, _ := createTestApp(t) + defer app.DB.Close() + + req := httptest.NewRequest("GET", "/books/1", nil) + vars := map[string]string{"id": "1"} + req = mux.SetURLVars(req, vars) + rr := httptest.NewRecorder() + + handler := http.HandlerFunc(app.DeleteBook) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusMethodNotAllowed, rr.Code) + assert.Contains(t, rr.Body.String(), "Only DELETE method is supported") +} + +func TestDeleteBook_FailedToDeleteAuthor(t *testing.T) { + app, mock := createTestApp(t) + defer app.DB.Close() + + req := httptest.NewRequest("DELETE", "/books/1", nil) + vars := map[string]string{"id": "1"} + req = mux.SetURLVars(req, vars) + rr := httptest.NewRecorder() + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT author_id FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnRows(sqlmock.NewRows([]string{"author_id"}).AddRow(1)) + + mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM books WHERE author_id = ? AND id != ?`)). + WithArgs(1, 1). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) + + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM books WHERE id = ?`)). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM authors WHERE id = ?`)). + WithArgs(1). + WillReturnError(fmt.Errorf("DB error")) + + handler := http.HandlerFunc(app.DeleteBook) + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusInternalServerError, rr.Code) + assert.Contains(t, rr.Body.String(), "Failed to delete author") + + err := mock.ExpectationsWereMet() + assert.NoError(t, err) +} +