package save_test import ( "bytes" "encoding/json" "errors" "fmt" "net/http" "net/http/httptest" "testing" "url-shortener/internal/http-server/handlers/url/save" "url-shortener/internal/http-server/handlers/url/save/mocks" "url-shortener/internal/lib/logger/handlers/slogdiscard" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestSaveHandler(t *testing.T) { cases := []struct { name string alias string url string respError string mockError error storageTimes int }{ { name: "Success", alias: "test_alias", url: "https://google.com", storageTimes: 1, }, { name: "Empty alias", alias: "", url: "https://google.com", storageTimes: 1, }, { name: "Empty URL", alias: "test_alias", url: "", respError: "field URL is a required field", storageTimes: 0, }, { name: "Invalid URL", alias: "test_alias", url: "invalid URL", respError: "field URL is not a valid url", storageTimes: 0, }, { name: "SaveURL Error", alias: "test_alias", url: "https://google.com", respError: "failed to add url", storageTimes: 1, mockError: errors.New("unexpected error"), }, } for _, tc := range cases { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() // создать мок urlSaver urlSaverMock := mocks.NewURLSaver(t) // описание поведения мока при вызове, если не ожидается respError или ожидается mockError (если вызовов не ноль) // if tc.respError == "" || tc.mockError != nil { if tc.storageTimes > 0 { urlSaverMock.On("SaveURL", tc.url, mock.AnythingOfType("string")).Return(tc.mockError).Times(tc.storageTimes) } // } // создать тестируемый handler, передаём discard logger и мок handler := save.New(slogdiscard.NewDiscardLogger(), urlSaverMock) // создаём json для теста input := fmt.Sprintf(`{"url": "%s", "alias": "%s"}`, tc.url, tc.alias) // создание http запроса к /save req, err := http.NewRequest(http.MethodPost, "/save", bytes.NewReader([]byte(input))) require.NoError(t, err) // recorder для ответов rr := httptest.NewRecorder() // обработать http запрос handler.ServeHTTP(rr, req) // сравнить ожидание и реальность require.Equal(t, rr.Code, http.StatusOK) // получить тело запроса body := rr.Body.String() var resp save.Response // Декодировать ответ в структуру require.NoError(t, json.Unmarshal([]byte(body), &resp)) // проверить ожидание и реальность require.Equal(t, tc.respError, resp.Error) // TODO: add more checks }) } }