diff --git a/internal/http-server/handlers/recipes/recipes_test.go b/internal/http-server/handlers/recipes/recipes_test.go index faf2c01..c24650f 100644 --- a/internal/http-server/handlers/recipes/recipes_test.go +++ b/internal/http-server/handlers/recipes/recipes_test.go @@ -34,7 +34,7 @@ func TestGetRecipesHandler(t *testing.T) { name: "Success", page: 1, inputBody: `{"page": 1}`, - wantBody: "{\"status\":\"OK\",\"recipes\":[{\"id\":1,\"title\":\"title 1\",\"img\":\"1.jpg\",\"ctime\":\"1 час\",\"cal\":\"100 kCal\"},{\"id\":2,\"title\":\"title 2\",\"img\":\"2.jpg\",\"ctime\":\"2 час\",\"cal\":\"200 kCal\"}]}\n", + wantBody: "{\"status\":\"OK\",\"recipes\":[{\"id\":1,\"title\":\"title 1\",\"img\":\"1.jpg\",\"ctime\":\"1 час\",\"cal\":\"100 kCal\"},{\"id\":2,\"title\":\"title 2\",\"img\":\"2.jpg\",\"ctime\":\"2 часа\",\"cal\":\"200 kCal\"}]}\n", wantRespStatus: "OK", storageTimes: 1, recipes: []models.Recipe{ @@ -49,7 +49,7 @@ func TestGetRecipesHandler(t *testing.T) { ID: 2, Title: "title 2", Image: "2.jpg", - CookingTime: "2 час", + CookingTime: "2 часа", Calories: "200 kCal", }, }, diff --git a/internal/http-server/handlers/recipesByCategory/recipesByCategory_test.go b/internal/http-server/handlers/recipesByCategory/recipesByCategory_test.go new file mode 100644 index 0000000..f8e68d5 --- /dev/null +++ b/internal/http-server/handlers/recipesByCategory/recipesByCategory_test.go @@ -0,0 +1,131 @@ +package recipes_by_category_test + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "recipes/internal/domain/models" + "recipes/internal/http-server/handlers/recipes" + recipes_by_category "recipes/internal/http-server/handlers/recipesByCategory" + "recipes/internal/http-server/handlers/recipesByCategory/mocks" + "recipes/internal/lib/logger/handlers/slogdiscard" + "recipes/internal/storage" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetRecipesByCategory(t *testing.T) { + cases := []struct { + name string // name of test + page uint // number of page to get + category string // category to get + inputBody string // input json + wantBody string // expected output json + wantRespError string // expected error + wantRespStatus string // expected status + storageMockError error // mock error to return + storageTimes int // count of storage calls + recipes []models.Recipe // returned data + }{ + { + name: "Success", + page: 1, + category: "test category", + inputBody: `{"page": 1, "category": "test category"}`, + wantBody: "{\"status\":\"OK\",\"recipes\":[{\"id\":1,\"title\":\"recipe 1\",\"img\":\"1.jpg\",\"ctime\":\"1 час\",\"cal\":\"100 kCal\"},{\"id\":2,\"title\":\"recipe 2\",\"img\":\"2.jpg\",\"ctime\":\"2 часа\",\"cal\":\"200 kCal\"}]}\n", + wantRespStatus: "OK", + storageTimes: 1, + recipes: []models.Recipe{ + { + ID: 1, + Title: "recipe 1", + Image: "1.jpg", + CookingTime: "1 час", + Calories: "100 kCal", + }, + { + ID: 2, + Title: "recipe 2", + Image: "2.jpg", + CookingTime: "2 часа", + Calories: "200 kCal", + }, + }, + }, + { + name: "Broken JSON", + inputBody: `{"p:1}`, + wantBody: "{\"status\":\"Error\",\"error\":\"failed to decode request\"}\n", + wantRespError: "failed to decode request", + wantRespStatus: "Error", + storageTimes: 0, + }, + { + name: "Bad data", + inputBody: `{"page": 0}`, + wantBody: "{\"status\":\"Error\",\"error\":\"field Page is a required field, field Category is a required field\"}\n", + wantRespError: "field Page is a required field, field Category is a required field", + wantRespStatus: "Error", + storageTimes: 0, + }, + { + name: "Category not found", + inputBody: `{"page": 1, "category": "some category"}`, + page: 1, + category: "some category", + wantBody: "{\"status\":\"Error\",\"error\":\"category not found\"}\n", + wantRespError: "category not found", + wantRespStatus: "Error", + storageMockError: storage.ErrCategoryNotFound, + storageTimes: 1, + }, + { + name: "Storage error", + inputBody: `{"page": 1, "category": "test category"}`, + page: 1, + category: "test category", + wantBody: "{\"status\":\"Error\",\"error\":\"failed to get recipes\"}\n", + wantRespError: "failed to get recipes", + wantRespStatus: "Error", + storageMockError: errors.New("SOME ERROR"), + storageTimes: 1, + }, + } + + for _, tc := range cases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + // create storage mock + recipeProviderMock := mocks.NewRecipesProvider(t) + if tc.storageTimes > 0 { + recipeProviderMock.On("GetRecipesByCategory", context.Background(), recipes_by_category.GetRecipesLimit*(int(tc.page)-1), recipes_by_category.GetRecipesLimit, tc.category).Return(tc.recipes, tc.storageMockError).Times(tc.storageTimes) + } + // create handler + handler := recipes_by_category.New(slogdiscard.NewDiscardLogger(), recipeProviderMock) + // http request + req, err := http.NewRequest(http.MethodGet, "/recipes_by_category", bytes.NewReader([]byte(tc.inputBody))) + require.NoError(t, err) + // create request + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + // compare expected and actual + assert.Equal(t, http.StatusOK, rr.Code) + + body := rr.Body.String() + assert.Equal(t, tc.wantBody, body) + + var resp recipes.Response + require.NoError(t, json.Unmarshal([]byte(body), &resp)) + assert.Equal(t, tc.wantRespError, resp.Error) + assert.Equal(t, tc.wantRespStatus, resp.Status) + assert.Equal(t, tc.recipes, resp.Recipes) + }) + } +}