diff --git a/pom.xml b/pom.xml
index 10fbe05..001dcbd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,6 +41,11 @@
gson
2.8.9
+
+ org.zalando
+ logbook-spring-boot-starter
+ 3.7.2
+
diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
index fc08be6..901f812 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
@@ -2,8 +2,10 @@
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.response.SuccessResponse;
import ru.yandex.practicum.filmorate.service.FilmService;
import java.util.Collection;
@@ -17,16 +19,39 @@ public class FilmController {
@GetMapping
public Collection getFilms() {
- return filmService.getFilms();
+ return filmService.getAllFilms();
+ }
+
+ @GetMapping("/{filmId}")
+ public Film getFilm(@PathVariable Long filmId) {
+ return filmService.getFilmById(filmId);
}
@PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
public Film addFilm(@Valid @RequestBody Film film) {
- return filmService.addFilm(film);
+ return filmService.createFilm(film);
}
@PutMapping
public Film updateFilm(@Valid @RequestBody Film newFilm) {
return filmService.updateFilm(newFilm);
}
+
+ @PutMapping("/{id}/like/{userId}")
+ public SuccessResponse likeFilm(@PathVariable Long id, @PathVariable Long userId) {
+ filmService.likeFilm(id, userId);
+ return new SuccessResponse();
+ }
+
+ @DeleteMapping("/{id}/like/{userId}")
+ public SuccessResponse removeLikeFilm(@PathVariable Long id, @PathVariable Long userId) {
+ filmService.removeLikeFilm(id, userId);
+ return new SuccessResponse();
+ }
+
+ @GetMapping("/popular")
+ public Collection getPopularFilms(@RequestParam(defaultValue = "10") int count) {
+ return filmService.getPopularFilms(count);
+ }
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
index 91af745..847c3c5 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
@@ -2,8 +2,10 @@
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.response.SuccessResponse;
import ru.yandex.practicum.filmorate.service.UserService;
import java.util.Collection;
@@ -17,16 +19,48 @@ public class UserController {
@GetMapping
public Collection getUsers() {
- return userService.getUsers();
+ return userService.getAllUsers();
+ }
+
+ @GetMapping("/{userId}")
+ public User getFilm(@PathVariable Long userId) {
+ return userService.getUserById(userId);
}
@PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
public User createUser(@Valid @RequestBody User user) {
- return userService.addUser(user);
+ return userService.createUser(user);
}
@PutMapping
public User updateUser(@Valid @RequestBody User newUser) {
return userService.updateUser(newUser);
}
+
+ @PutMapping("/{id}/friends/{friendId}")
+ public SuccessResponse addFriend(@PathVariable Long id, @PathVariable Long friendId) {
+ userService.addFriend(id, friendId);
+ return new SuccessResponse();
+ }
+
+ @DeleteMapping("/{id}/friends/{friendId}")
+ public SuccessResponse removeFriend(@PathVariable Long id, @PathVariable Long friendId) {
+ userService.removeFriend(id, friendId);
+ return new SuccessResponse();
+ }
+
+ @GetMapping("/{id}/friends")
+ public Collection getFriends(@PathVariable Long id) {
+ return userService.getUserFriends(id);
+ }
+
+ @GetMapping("/{id}/friends/common/{otherId}")
+ public Collection getCommonFriends(@PathVariable Long id, @PathVariable Long otherId) {
+ return userService.getCommonUserFriends(id, otherId);
+ }
+
+
+
+
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java
index dd8d262..417433b 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java
@@ -1,6 +1,12 @@
package ru.yandex.practicum.filmorate.exception;
+import lombok.Getter;
+
+
+@Getter
public class NotFoundException extends RuntimeException {
+ public String name = "not found";
+
public NotFoundException(String message) {
super(message);
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/OtherException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/OtherException.java
new file mode 100644
index 0000000..e9694c1
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/exception/OtherException.java
@@ -0,0 +1,12 @@
+package ru.yandex.practicum.filmorate.exception;
+
+import lombok.Getter;
+
+@Getter
+public class OtherException extends RuntimeException {
+ String name = "server error";
+
+ public OtherException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java
index 52dc49c..d578df8 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java
@@ -1,6 +1,11 @@
package ru.yandex.practicum.filmorate.exception;
+import lombok.Getter;
+
+@Getter
public class ValidationException extends RuntimeException {
+ String name = "validation error";
+
public ValidationException(String message) {
super(message);
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/handler/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/handler/ErrorHandler.java
new file mode 100644
index 0000000..85b72a5
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/handler/ErrorHandler.java
@@ -0,0 +1,52 @@
+package ru.yandex.practicum.filmorate.handler;
+
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.exception.OtherException;
+import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.response.ErrorResponse;
+
+import java.util.List;
+
+@Slf4j
+@RestControllerAdvice
+public class ErrorHandler {
+
+ @ExceptionHandler
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ public ErrorResponse handleNotFound(final NotFoundException e) {
+ return new ErrorResponse(e.getName(), e.getMessage());
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleValidationException(MethodArgumentNotValidException ex) {
+ List errors = ex.getBindingResult().getFieldErrors().stream()
+ .map(FieldError::getDefaultMessage)
+ .toList();
+ String message = String.join("\n", errors);
+ log.warn("Ошибка валидации: {}", errors);
+
+ return new ErrorResponse("validation error", message);
+ }
+
+ @ExceptionHandler
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handleValidationError(final ValidationException e) {
+ return new ErrorResponse(e.getName(), e.getMessage());
+ }
+
+ @ExceptionHandler
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ public ErrorResponse handleInternalServerError(final OtherException e) {
+ return new ErrorResponse(e.getName(), e.getMessage());
+ }
+
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/handler/GlobalExceptionHandler.java b/src/main/java/ru/yandex/practicum/filmorate/handler/GlobalExceptionHandler.java
deleted file mode 100644
index 306285b..0000000
--- a/src/main/java/ru/yandex/practicum/filmorate/handler/GlobalExceptionHandler.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package ru.yandex.practicum.filmorate.handler;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.validation.FieldError;
-import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.RestControllerAdvice;
-import ru.yandex.practicum.filmorate.exception.ValidationException;
-
-import java.util.List;
-
-@Slf4j
-@RestControllerAdvice
-public class GlobalExceptionHandler {
-
- @ExceptionHandler(MethodArgumentNotValidException.class)
- public void handleValidationException(MethodArgumentNotValidException ex) {
- List errors = ex.getBindingResult().getFieldErrors().stream()
- .map(FieldError::getDefaultMessage)
- .toList();
- String message = String.join("\n", errors);
- log.warn("Ошибка валидации: {}", errors);
- throw new ValidationException(message);
- }
-}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
index 6283263..660004b 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
@@ -2,19 +2,22 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.*;
-import lombok.AllArgsConstructor;
import lombok.Data;
+import lombok.NoArgsConstructor;
import java.time.LocalDate;
+import java.util.HashSet;
+import java.util.Set;
/**
* Film.
*/
@Data
-@AllArgsConstructor
+@NoArgsConstructor
public class Film {
private Long id;
+ private Set usersLikes = new HashSet<>();
@NotBlank(message = "Название фильма не может быть пустым")
private String name;
@@ -27,6 +30,14 @@ public class Film {
@Positive(message = "Продолжительность фильма должна быть положительным числом")
private Integer duration;
+ public Film(Long id, String name, String description, LocalDate releaseDate, Integer duration) {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ this.releaseDate = releaseDate;
+ this.duration = duration;
+ }
+
@AssertTrue(message = "Дата релиза фильма должна быть не раньше 28 декабря 1895 года")
@JsonIgnore
public boolean isReleaseDateValid() {
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/User.java b/src/main/java/ru/yandex/practicum/filmorate/model/User.java
index 9eee6fb..95c2eda 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java
@@ -4,19 +4,22 @@
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.PastOrPresent;
import jakarta.validation.constraints.Pattern;
-import lombok.AllArgsConstructor;
import lombok.Data;
+import lombok.NoArgsConstructor;
import java.time.LocalDate;
+import java.util.HashSet;
+import java.util.Set;
/**
* User.
*/
@Data
-@AllArgsConstructor
+@NoArgsConstructor
public class User {
private Long id;
+ private Set friends = new HashSet<>();
@Email(message = "Электронная почта пользователя должна соответствовать формату электронного адреса")
@NotBlank(message = "Электронная почта пользователя не может быть пустой")
@@ -29,4 +32,12 @@ public class User {
@PastOrPresent(message = "Дата рождения пользователя не может быть в будущем")
private LocalDate birthday;
+
+ public User(Long id, String email, String login, String name, LocalDate birthday) {
+ this.id = id;
+ this.email = email;
+ this.login = login;
+ this.name = name;
+ this.birthday = birthday;
+ }
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/response/ErrorResponse.java b/src/main/java/ru/yandex/practicum/filmorate/response/ErrorResponse.java
new file mode 100644
index 0000000..1707772
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/response/ErrorResponse.java
@@ -0,0 +1,12 @@
+package ru.yandex.practicum.filmorate.response;
+
+
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+
+@Data
+@RequiredArgsConstructor
+public class ErrorResponse {
+ private final String error;
+ private final String message;
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/response/SuccessResponse.java b/src/main/java/ru/yandex/practicum/filmorate/response/SuccessResponse.java
new file mode 100644
index 0000000..be025ad
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/response/SuccessResponse.java
@@ -0,0 +1,10 @@
+package ru.yandex.practicum.filmorate.response;
+
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+
+@Data
+@RequiredArgsConstructor
+public class SuccessResponse {
+ private final String status = "success";
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
index 983a303..6cfb0e6 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
@@ -1,34 +1,38 @@
package ru.yandex.practicum.filmorate.service;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.exception.OtherException;
import ru.yandex.practicum.filmorate.exception.ValidationException;
import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.storage.film.FilmStorage;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
+import java.util.Comparator;
@Service
@Slf4j
+@RequiredArgsConstructor
public class FilmService {
- private final Map films = new HashMap<>();
+ private final FilmStorage filmStorage;
+ private final UserService userService;
+ private final Comparator filmComparator = Comparator.comparing((Film film) -> film.getUsersLikes().size()).reversed();
- public Collection getFilms() {
- return films.values();
+
+ public Collection getAllFilms() {
+ return filmStorage.getFilms();
}
- public Map getFilmsMap() {
- return films;
+ public Film getFilmById(Long id) {
+ return filmStorage.getFilm(id).orElseThrow(() -> new NotFoundException("Фильм с id " + id + " не найден"));
}
- public Film addFilm(Film film) {
- film.setId(getNextId());
- films.put(film.getId(), film);
+ public Film createFilm(Film film) {
log.info("Добавлен фильм: {}", film);
- return film;
+ return filmStorage.addFilm(film);
+
}
public Film updateFilm(Film newFilm) {
@@ -36,30 +40,39 @@ public Film updateFilm(Film newFilm) {
log.warn("В запросе на обновление фильма не передан id");
throw new ValidationException("Id не может быть пустым");
}
- if (films.containsKey(newFilm.getId())) {
- Film oldFilm = films.get(newFilm.getId());
- Optional.ofNullable(newFilm.getName()).ifPresent(oldFilm::setName);
- Optional.ofNullable(newFilm.getDescription()).ifPresent(oldFilm::setDescription);
- Optional.ofNullable(newFilm.getReleaseDate()).ifPresent(oldFilm::setReleaseDate);
- Optional.ofNullable(newFilm.getDuration()).ifPresent(oldFilm::setDuration);
- log.info("Обновлен фильм: {}", oldFilm);
- return oldFilm;
- } else {
- log.warn("В запросе на обновление фильма передан неизвестный id - {}", newFilm.getId());
- throw new NotFoundException("Фильм с id " + newFilm.getId() + " не найден");
+
+ filmStorage.getFilm(newFilm.getId())
+ .orElseThrow(() -> {
+ log.warn("В запросе на обновление фильма передан неизвестный id - {}", newFilm.getId());
+ return new NotFoundException("Фильм с id " + newFilm.getId() + " не найден");
+ });
+
+ return filmStorage.updateFilm(newFilm);
+ }
+
+ public void likeFilm(Long filmId, Long userId) {
+ if (!getFilmById(filmId).getUsersLikes().add(userService.getUserById(userId).getId())) {
+ log.warn("Пользователь с id {} уже ставил лайк фильму с id {}", userId, filmId);
+ throw new OtherException("Пользователь уже ставил лайк фильму");
}
+
+ log.info("Пользователь с id {} поставил лайк фильму с id {}", userId, filmId);
+ }
+
+ public void removeLikeFilm(Long filmId, Long userId) {
+ if (!getFilmById(filmId).getUsersLikes().remove(userService.getUserById(userId).getId())) {
+ log.warn("Пользователь с id {} не ставил лайк фильму id {}", userId, filmId);
+ throw new OtherException("Пользователь не ставил лайк фильму");
+ }
+
+ log.info("Пользователь с id {} удалил свой лайк у фильма с id {}", userId, filmId);
}
- public void clearData() {
- films.clear();
+ public Collection getPopularFilms(int count) {
+ return filmStorage.getFilms().stream().sorted(filmComparator).limit(count).toList();
}
- private long getNextId() {
- long currentMaxId = films.keySet()
- .stream()
- .mapToLong(id -> id)
- .max()
- .orElse(0);
- return ++currentMaxId;
+ public void clearFilmsData() {
+ filmStorage.clearData();
}
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
index 4c204ab..5d38853 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
@@ -1,39 +1,38 @@
package ru.yandex.practicum.filmorate.service;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.exception.OtherException;
import ru.yandex.practicum.filmorate.exception.ValidationException;
import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.storage.user.UserStorage;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
@Service
@Slf4j
+@RequiredArgsConstructor
public class UserService {
- private final Map users = new HashMap<>();
+ private final UserStorage userStorage;
- public Collection getUsers() {
- return users.values();
+ public Collection getAllUsers() {
+ return userStorage.getUsers();
}
- public Map getUsersMap() {
- return users;
+ public User getUserById(Long id) {
+ return userStorage.getUser(id).orElseThrow(() -> new NotFoundException("Юзер с id " + id + " не найден"));
}
- public User addUser(User user) {
- user.setId(getNextId());
+ public User createUser(User user) {
if (user.getName() == null || user.getName().isBlank()) {
user.setName(user.getLogin());
log.info("В запросе создания пользователя передан пустой name. Для поля name использован логин {}",
user.getLogin());
}
- users.put(user.getId(), user);
- log.info("Добавлен пользователь: {}", user);
- return user;
+
+ return userStorage.addUser(user);
}
public User updateUser(User newUser) {
@@ -41,36 +40,64 @@ public User updateUser(User newUser) {
log.warn("В запросе на обновление юзера не передан id");
throw new ValidationException("Id не может быть пустым");
}
- if (users.containsKey(newUser.getId())) {
- User oldUser = users.get(newUser.getId());
- if (newUser.getName() == null || newUser.getName().isBlank()) {
- oldUser.setName(newUser.getLogin());
- log.info("В запросе обновления пользователя передан пустой name. Для поля name использован логин {}",
- newUser.getLogin());
- } else {
- Optional.of(newUser.getName()).ifPresent(oldUser::setName);
- }
- Optional.ofNullable(newUser.getEmail()).ifPresent(oldUser::setEmail);
- Optional.ofNullable(newUser.getBirthday()).ifPresent(oldUser::setBirthday);
- Optional.ofNullable(newUser.getLogin()).ifPresent(oldUser::setLogin);
- log.info("Обновлен юзер: {}", oldUser);
- return oldUser;
- } else {
- log.warn("В запросе на обновление пользователя передан неизвестный id - {}", newUser.getId());
- throw new NotFoundException("Пользователь с id " + newUser.getId() + " не найден");
+
+ userStorage.getUser(newUser.getId())
+ .orElseThrow(() -> {
+ log.warn("В запросе на обновление пользователя передан неизвестный id - {}", newUser.getId());
+ return new NotFoundException("Пользователь с id " + newUser.getId() + " не найден");
+ });
+
+ if (newUser.getName() == null || newUser.getName().isBlank()) {
+ newUser.setName(newUser.getLogin());
+ log.info("В запросе обновления пользователя передан пустой name. Для поля name использован логин {}",
+ newUser.getLogin());
+ }
+
+ return userStorage.updateUser(newUser);
+
+
+ }
+
+ public void addFriend(Long id, Long friendId) {
+ User user = getUserById(id);
+ User friend = getUserById(friendId);
+
+ if (id.equals(friendId)) {
+ log.warn("Пользователь не может добавить сам себя в друзья");
+ throw new OtherException("Пользователь не может добавить сам себя в друзья");
+ }
+
+ if (!user.getFriends().add(friendId) || !friend.getFriends().add(id)) {
+ log.warn("Пользователи с id {} и id {} уже являются друзьями", id, friendId);
+ throw new OtherException("Пользователи уже являются друзьями");
+ }
+
+ log.info("Пользователь с id {} добавил в друзья пользователя с id {}", id, friendId);
+ }
+
+ public void removeFriend(Long id, Long friendId) {
+ User user = getUserById(id);
+ User friend = getUserById(friendId);
+
+ if (!user.getFriends().remove(friendId) || !friend.getFriends().remove(id)) {
+ log.warn("У пользователя с id {} не найден друг с id {}", id, friendId);
}
+
+ log.info("Пользователь с id {} удалил из друзей пользователя с id {}", id, friendId);
+ }
+
+ public Collection getUserFriends(Long id) {
+ return getUserById(id).getFriends().stream()
+ .map(this::getUserById).toList();
}
- public void clearData() {
- users.clear();
+ public Collection getCommonUserFriends(Long id, Long otherId) {
+ return getUserById(id).getFriends().stream()
+ .filter(getUserById(otherId).getFriends()::contains)
+ .map(this::getUserById).toList();
}
- private long getNextId() {
- long currentMaxId = users.keySet()
- .stream()
- .mapToLong(id -> id)
- .max()
- .orElse(0);
- return ++currentMaxId;
+ public void clearUsersData() {
+ userStorage.clearData();
}
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java
new file mode 100644
index 0000000..1880bcb
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java
@@ -0,0 +1,21 @@
+package ru.yandex.practicum.filmorate.storage.film;
+
+import ru.yandex.practicum.filmorate.model.Film;
+
+import java.util.Collection;
+import java.util.Optional;
+
+public interface FilmStorage {
+
+ Film addFilm(Film film);
+
+ Film updateFilm(Film film);
+
+ Collection getFilms();
+
+ Optional getFilm(Long id);
+
+ void clearData();
+
+
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java
new file mode 100644
index 0000000..a91d713
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java
@@ -0,0 +1,58 @@
+package ru.yandex.practicum.filmorate.storage.film;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import ru.yandex.practicum.filmorate.model.Film;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+@Component
+@Slf4j
+public class InMemoryFilmStorage implements FilmStorage {
+
+ private final Map films = new HashMap<>();
+
+ public Collection getFilms() {
+ return films.values();
+ }
+
+ public Optional getFilm(Long id) {
+ return films.values().stream()
+ .filter(film -> film.getId().equals(id))
+ .findFirst();
+ }
+
+ public Film addFilm(Film film) {
+ film.setId(getNextId());
+ films.put(film.getId(), film);
+ log.info("Добавлен фильм: {}", film);
+ return film;
+ }
+
+ public Film updateFilm(Film newFilm) {
+ Film oldFilm = films.get(newFilm.getId());
+ Optional.ofNullable(newFilm.getName()).ifPresent(oldFilm::setName);
+ Optional.ofNullable(newFilm.getDescription()).ifPresent(oldFilm::setDescription);
+ Optional.ofNullable(newFilm.getReleaseDate()).ifPresent(oldFilm::setReleaseDate);
+ Optional.ofNullable(newFilm.getDuration()).ifPresent(oldFilm::setDuration);
+ log.info("Обновлен фильм: {}", newFilm);
+ return oldFilm;
+ }
+
+ private long getNextId() {
+ long currentMaxId = films.keySet()
+ .stream()
+ .mapToLong(id -> id)
+ .max()
+ .orElse(0);
+ return ++currentMaxId;
+ }
+
+ public void clearData() {
+ films.clear();
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java
new file mode 100644
index 0000000..76fae6a
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java
@@ -0,0 +1,57 @@
+package ru.yandex.practicum.filmorate.storage.user;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+@Component
+@Slf4j
+public class InMemoryUserStorage implements UserStorage {
+
+ private final Map users = new HashMap<>();
+
+ public Collection getUsers() {
+ return users.values();
+ }
+
+ public Optional getUser(Long id) {
+ return users.values().stream()
+ .filter(user -> user.getId().equals(id))
+ .findFirst();
+ }
+
+ public User addUser(User user) {
+ user.setId(getNextId());
+ users.put(user.getId(), user);
+ log.info("Добавлен пользователь: {}", user);
+ return user;
+ }
+
+ public User updateUser(User newUser) {
+ User oldUser = users.get(newUser.getId());
+ Optional.of(newUser.getName()).ifPresent(oldUser::setName);
+ Optional.ofNullable(newUser.getEmail()).ifPresent(oldUser::setEmail);
+ Optional.ofNullable(newUser.getBirthday()).ifPresent(oldUser::setBirthday);
+ Optional.ofNullable(newUser.getLogin()).ifPresent(oldUser::setLogin);
+ log.info("Обновлен юзер: {}", newUser);
+ return oldUser;
+ }
+
+ public void clearData() {
+ users.clear();
+ }
+
+ private long getNextId() {
+ long currentMaxId = users.keySet()
+ .stream()
+ .mapToLong(id -> id)
+ .max()
+ .orElse(0);
+ return ++currentMaxId;
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserStorage.java
new file mode 100644
index 0000000..11dd5fa
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserStorage.java
@@ -0,0 +1,19 @@
+package ru.yandex.practicum.filmorate.storage.user;
+
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.util.Collection;
+import java.util.Optional;
+
+public interface UserStorage {
+
+ User addUser(User user);
+
+ User updateUser(User user);
+
+ Collection getUsers();
+
+ Optional getUser(Long id);
+
+ void clearData();
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 4b49e8e..10f7117 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1 +1,2 @@
-logging.level.root=INFO
\ No newline at end of file
+logging.level.root=INFO
+logging.level.org.zalando.logbook= TRACE
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java
index 87bf814..1b93f1c 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java
@@ -1,38 +1,54 @@
package ru.yandex.practicum.filmorate;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParser;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
+import org.springframework.http.*;
+import org.springframework.test.web.servlet.MockMvc;
import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.User;
import ru.yandex.practicum.filmorate.service.FilmService;
+import ru.yandex.practicum.filmorate.service.UserService;
import java.time.LocalDate;
-import java.util.Objects;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@SpringBootTest
+@AutoConfigureMockMvc
class FilmControllerTest {
@Autowired
- private TestRestTemplate restTemplate;
+ private MockMvc mockMvc;
@Autowired
private FilmService filmService;
- private final HttpHeaders headers = new HttpHeaders();
+ @Autowired
+ private UserService userService;
+
+ @BeforeEach
+ void setUp() {
+ filmService.createFilm(new Film(1L, "test1", "test_descr1", LocalDate.of(1900, 12, 25), 10));
+ filmService.createFilm(new Film(2L, "test2", "test_descr2", LocalDate.of(1900, 12, 25), 10));
+ userService.createUser(new User(1L, "test@mail.ru", "testlogin1", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(2L, "test2@mail.ru", "testlogin2", "testname2", LocalDate.of(1901, 10, 21)));
+ }
+
+ @AfterEach
+ void tearDown() {
+ filmService.clearFilmsData();
+ userService.clearUsersData();
+ }
static Stream provideInvalidFilmJsonCreate() {
return Stream.of(
@@ -123,173 +139,296 @@ static Stream provideInvalidFilmJsonUpdate() {
" \"description\": \"Sci-fi action\",\n" +
" \"releaseDate\": \"1900-12-25\",\n" +
" \"duration\": -5\n" +
- "}" // Отрицательная длительность
- );
- }
+ "}", // Отрицательная длительность
- static Stream provideInvalidFilmJsonIdUpdate() {
- return Stream.of(
"{\n" +
+ " \"id\": 135,\n" +
" \"name\": \"The Matrix\",\n" +
" \"description\": \"Sci-fi action\",\n" +
" \"releaseDate\": \"1900-12-25\",\n" +
- " \"duration\": 10\n" +
- "}", // Без id
-
- "{\n" +
- " \"id\": 125,\n" +
- " \"name\": \"The Matrix\",\n" +
- " \"description\": \"Sci-fi action\",\n" +
- " \"releaseDate\": \"1900-12-25\",\n" +
- " \"duration\": 10\n" +
- "}" // Id нет в списке
+ " \"duration\": -5\n" +
+ "}" // неизвестный ид
);
}
@Test
- void contextLoads() {
+ void getFilms() throws Exception {
+ mockMvc.perform(get("/films"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$[0].id").value(1))
+ .andExpect(jsonPath("$[0].name").value("test1"))
+ .andExpect(jsonPath("$[1].id").value(2))
+ .andExpect(jsonPath("$[1].name").value("test2"));
}
- @BeforeEach
- void setUp() {
- headers.set("Content-Type", "application/json");
- filmService.clearData();
+ @Test
+ void getFilmById() throws Exception {
+ mockMvc.perform(get("/films/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.id").value(1))
+ .andExpect(jsonPath("$.name").value("test1"));
}
@Test
- void getFilms() {
- filmService.addFilm(new Film(1L, "The Matrix", "Sci-fi action",
- LocalDate.of(1900, 12, 25), 10));
- filmService.addFilm(new Film(2L, "The Dark Knight", "Superhero thriller",
- LocalDate.of(1900, 12, 25), 10));
- ResponseEntity response = restTemplate.getForEntity("/films", String.class);
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
- JsonElement expectedJson = JsonParser.parseString(
- "[\n" +
- " {\n" +
- " \"id\": 1,\n" +
- " \"name\": \"The Matrix\",\n" +
- " \"description\": \"Sci-fi action\",\n" +
- " \"releaseDate\": \"1900-12-25\",\n" +
- " \"duration\": 10\n" +
- " },\n" +
- " {\n" +
- " \"id\": 2,\n" +
- " \"name\": \"The Dark Knight\",\n" +
- " \"description\": \"Superhero thriller\",\n" +
- " \"releaseDate\": \"1900-12-25\",\n" +
- " \"duration\": 10\n" +
- " }\n" +
- "]"
- );
- assertEquals(expectedJson, JsonParser.parseString(response.getBody()));
+ void getUnknownFilmById() throws Exception {
+ mockMvc.perform(get("/films/5"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.error").value("not found"))
+ .andExpect(jsonPath("$.message").value("Фильм с id 5 не найден"));
}
@Test
- void addFilm() {
+ void addFilms() throws Exception {
String json = "{\n" +
" \"name\": \"The Matrix\",\n" +
" \"description\": \"Sci-fi action\",\n" +
" \"releaseDate\": \"1967-03-25\",\n" +
" \"duration\": 100\n" +
"}";
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/films", HttpMethod.POST, entity, String.class);
- assertEquals(HttpStatus.OK, response.getStatusCode());
+ mockMvc.perform(post("/films")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.id").value(3))
+ .andExpect(jsonPath("$.name").value("The Matrix"));
- assertNotNull(response.getBody());
- JsonElement expectedJson = JsonParser.parseString(
- "{\n" +
- " \"id\": 1,\n" +
- " \"name\": \"The Matrix\",\n" +
- " \"description\": \"Sci-fi action\",\n" +
- " \"releaseDate\": \"1967-03-25\",\n" +
- " \"duration\": 100\n" +
- "}"
- );
- Film createdFilm = filmService.getFilmsMap().get(1L);
- assertNotNull(createdFilm);
- assertEquals(expectedJson, JsonParser.parseString(response.getBody()));
- assertEquals(1L, createdFilm.getId());
- assertEquals("The Matrix", createdFilm.getName());
- assertEquals("Sci-fi action", createdFilm.getDescription());
- assertEquals(LocalDate.of(1967, 3, 25), createdFilm.getReleaseDate());
- assertEquals(100, createdFilm.getDuration());
+ assertEquals(filmService.getFilmById(3L).getName(), "The Matrix");
}
@Test
- void updateFilm() {
- filmService.addFilm(new Film(1L, "The Matrix", "Sci-fi action",
- LocalDate.of(1900, 12, 25), 10));
+ void updateFilms() throws Exception {
String json = "{\n" +
" \"id\": 1,\n" +
- " \"name\": \"The Matrix updated\",\n" +
- " \"description\": \"Sci-fi action updated\",\n" +
+ " \"name\": \"test1_upd\",\n" +
+ " \"description\": \"test_descr1_upd\",\n" +
" \"releaseDate\": \"1967-03-25\",\n" +
" \"duration\": 100\n" +
"}";
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/films", HttpMethod.PUT, entity, String.class);
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
- JsonElement expectedJson = JsonParser.parseString(json);
- assertEquals(expectedJson, JsonParser.parseString(response.getBody()));
- Film updatedFilm = filmService.getFilmsMap().get(1L);
- assertNotNull(updatedFilm);
- assertEquals(1L, updatedFilm.getId());
- assertEquals("The Matrix updated", updatedFilm.getName());
- assertEquals("Sci-fi action updated", updatedFilm.getDescription());
- assertEquals(LocalDate.of(1967, 3, 25), updatedFilm.getReleaseDate());
- assertEquals(100, updatedFilm.getDuration());
+
+ mockMvc.perform(put("/films")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.id").value(1))
+ .andExpect(jsonPath("$.name").value("test1_upd"));
+
+ assertEquals("test1_upd", filmService.getFilmById(1L).getName());
+ assertEquals("test_descr1_upd", filmService.getFilmById(1L).getDescription());
+ assertEquals("1967-03-25", filmService.getFilmById(1L).getReleaseDate().toString());
+ assertEquals(100, filmService.getFilmById(1L).getDuration());
}
@ParameterizedTest
@MethodSource("provideInvalidFilmJsonCreate")
- void addFilmValidation(String json) {
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/films", HttpMethod.POST, entity, String.class);
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Bad Request\""));
+ void addFilmValidation(String json) throws Exception {
+ mockMvc.perform(post("/films")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
}
@Test
- void addFilmEmptyJson() {
- HttpEntity entity = new HttpEntity<>(null, headers);
- ResponseEntity response = restTemplate.exchange("/films", HttpMethod.POST, entity, String.class);
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Bad Request\""));
+ void addFilmEmptyJson() throws Exception {
+ String json = "{}";
+
+ mockMvc.perform(post("/films")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
}
@ParameterizedTest
@MethodSource("provideInvalidFilmJsonUpdate")
- void updateFilmValidation(String json) {
- filmService.addFilm(new Film(1L, "The Matrix", "Sci-fi action",
- LocalDate.of(1900, 12, 25), 10));
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/films", HttpMethod.PUT, entity, String.class);
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Bad Request\""));
+ void updateFilmValidation(String json) throws Exception {
+ mockMvc.perform(put("/films")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
}
- @ParameterizedTest
- @MethodSource("provideInvalidFilmJsonIdUpdate")
- void updateFilmIdValidation(String json) {
- filmService.addFilm(new Film(1L, "The Matrix", "Sci-fi action",
- LocalDate.of(1900, 12, 25), 10));
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/films", HttpMethod.PUT, entity, String.class);
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Internal Server Error\""));
+ @Test
+ void updateFilmWithoutId() throws Exception {
+ String json = "{\n" +
+ " \"name\": \"The Matrix\",\n" +
+ " \"description\": \"Sci-fi action\",\n" +
+ " \"releaseDate\": \"1900-12-25\",\n" +
+ " \"duration\": 10\n" +
+ "}";
+
+ mockMvc.perform(put("/films")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
}
@Test
- void updateFilmEmptyJson() {
- filmService.addFilm(new Film(1L, "The Matrix", "Sci-fi action",
- LocalDate.of(1900, 12, 25), 10));
- HttpEntity entity = new HttpEntity<>(null, headers);
- ResponseEntity response = restTemplate.exchange("/films", HttpMethod.PUT, entity, String.class);
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Bad Request\""));
+ void updateFilmEmptyJson() throws Exception {
+ String json = "{}";
+
+ mockMvc.perform(put("/films")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
+ }
+
+ @Test
+ void likeFilm() throws Exception {
+
+ mockMvc.perform(put("/films/1/like/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("success"));
+
+ mockMvc.perform(put("/films/1/like/2"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("success"));
+
+ assertEquals(2, filmService.getFilmById(1L).getUsersLikes().size());
+ }
+
+ @Test
+ void deleteFilm() throws Exception {
+ filmService.likeFilm(1L, 1L);
+ filmService.likeFilm(1L, 2L);
+ mockMvc.perform(delete("/films/1/like/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("success"));
+
+ mockMvc.perform(delete("/films/1/like/2"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("success"));
+
+ assertEquals(0, filmService.getFilmById(1L).getUsersLikes().size());
+ }
+
+ @Test
+ void likeUnknownFilm() throws Exception {
+ mockMvc.perform(put("/films/4/like/1"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.error").value("not found"))
+ .andExpect(jsonPath("$.message").value("Фильм с id 4 не найден"));
+ }
+
+ @Test
+ void likeFilmUnkownUser() throws Exception {
+ mockMvc.perform(put("/films/1/like/4"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.error").value("not found"))
+ .andExpect(jsonPath("$.message").value("Юзер с id 4 не найден"));
+ }
+
+ @Test
+ void deleteLikeFilm() throws Exception {
+ filmService.likeFilm(1L, 1L);
+ mockMvc.perform(delete("/films/1/like/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("success"));
+
+ assertEquals(0, filmService.getFilmById(1L).getUsersLikes().size());
+ }
+
+ @Test
+ void deleteUnknownLikeFilm() throws Exception {
+ mockMvc.perform(delete("/films/1/like/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.error").value("server error"))
+ .andExpect(jsonPath("$.message").value("Пользователь не ставил лайк фильму"));
}
+
+ @Test
+ void deleteLikeFilmUnkownUser() throws Exception {
+ mockMvc.perform(delete("/films/1/like/4"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.error").value("not found"))
+ .andExpect(jsonPath("$.message").value("Юзер с id 4 не найден"));
+ }
+
+ @Test
+ void deleteLikeFilmUnkownFilm() throws Exception {
+ mockMvc.perform(delete("/films/4/like/1"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.error").value("not found"))
+ .andExpect(jsonPath("$.message").value("Фильм с id 4 не найден"));
+ }
+
+ @Test
+ void get3PopularFilms() throws Exception {
+ filmService.createFilm(new Film(3L, "test3", "test_descr3", LocalDate.of(1900, 12, 25), 10));
+ filmService.createFilm(new Film(4L, "test4", "test_descr4", LocalDate.of(1900, 12, 25), 10));
+ userService.createUser(new User(3L, "test3@mail.ru", "testlogin3", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(4L, "test4@mail.ru", "testlogin4", "testname2", LocalDate.of(1901, 10, 21)));
+ filmService.createFilm(new Film(5L, "test5", "test_descr5", LocalDate.of(1900, 12, 25), 10));
+ filmService.createFilm(new Film(6L, "test6", "test_descr6", LocalDate.of(1900, 12, 25), 10));
+ userService.createUser(new User(5L, "test5@mail.ru", "testlogin5", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(6L, "test6@mail.ru", "testlogin6 ", "testname2", LocalDate.of(1901, 10, 21)));
+ filmService.likeFilm(3L, 1L);
+ filmService.likeFilm(3L, 2L);
+ filmService.likeFilm(3L, 3L);
+ filmService.likeFilm(3L, 4L);
+ filmService.likeFilm(1L, 5L);
+ filmService.likeFilm(1L, 6L);
+ filmService.likeFilm(4L, 6L);
+ filmService.likeFilm(2L, 1L);
+ filmService.likeFilm(2L, 2L);
+ mockMvc.perform(get("/films/popular?count=3"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.length()").value(3))
+ .andExpect(jsonPath("$[0].id").value(3))
+ .andExpect(jsonPath("$[1].name").value("test1"))
+ .andExpect(jsonPath("$[2].description").value("test_descr2"));
+ }
+
+ @Test
+ void getDefaultPopularFilms() throws Exception {
+ filmService.createFilm(new Film(3L, "test3", "test_descr3", LocalDate.of(1900, 12, 25), 10));
+ filmService.createFilm(new Film(4L, "test4", "test_descr4", LocalDate.of(1900, 12, 25), 10));
+ userService.createUser(new User(3L, "test3@mail.ru", "testlogin3", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(4L, "test4@mail.ru", "testlogin4", "testname2", LocalDate.of(1901, 10, 21)));
+ filmService.createFilm(new Film(5L, "test5", "test_descr5", LocalDate.of(1900, 12, 25), 10));
+ filmService.createFilm(new Film(6L, "test6", "test_descr6", LocalDate.of(1900, 12, 25), 10));
+ userService.createUser(new User(5L, "test5@mail.ru", "testlogin5", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(6L, "test6@mail.ru", "testlogin6 ", "testname2", LocalDate.of(1901, 10, 21)));
+ filmService.createFilm(new Film(7L, "test7", "test_descr7", LocalDate.of(1900, 12, 25), 10));
+ filmService.createFilm(new Film(8L, "test8", "test_descr8", LocalDate.of(1900, 12, 25), 10));
+ userService.createUser(new User(7L, "test7@mail.ru", "testlogin7", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(8L, "test8@mail.ru", "testlogin8", "testname2", LocalDate.of(1901, 10, 21)));
+ filmService.createFilm(new Film(9L, "test9", "test_descr9", LocalDate.of(1900, 12, 25), 10));
+ filmService.createFilm(new Film(10L, "test10", "test_descr10", LocalDate.of(1900, 12, 25), 10));
+ userService.createUser(new User(9L, "test9@mail.ru", "testlogin9", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(10L, "test10@mail.ru", "testlogin10 ", "testname2", LocalDate.of(1901, 10, 21)));
+ filmService.createFilm(new Film(11L, "test11", "test_descr11", LocalDate.of(1900, 12, 25), 10));
+ filmService.createFilm(new Film(12L, "test12", "test_descr12", LocalDate.of(1900, 12, 25), 10));
+ userService.createUser(new User(11L, "test11@mail.ru", "testlogin11", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(12L, "test12@mail.ru", "testlogin12", "testname2", LocalDate.of(1901, 10, 21)));
+ filmService.createFilm(new Film(13L, "test13", "test_descr13", LocalDate.of(1900, 12, 25), 10));
+ filmService.createFilm(new Film(14L, "test14", "test_descr14", LocalDate.of(1900, 12, 25), 10));
+ userService.createUser(new User(13L, "test13@mail.ru", "testlogin13", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(14L, "test14@mail.ru", "testlogin14 ", "testname2", LocalDate.of(1901, 10, 21)));
+ filmService.likeFilm(3L, 1L);
+ filmService.likeFilm(3L, 2L);
+ filmService.likeFilm(3L, 3L);
+ filmService.likeFilm(3L, 4L);
+ filmService.likeFilm(1L, 5L);
+ filmService.likeFilm(1L, 6L);
+ filmService.likeFilm(4L, 6L);
+ filmService.likeFilm(5L, 1L);
+ filmService.likeFilm(5L, 2L);
+ filmService.likeFilm(6L, 1L);
+ filmService.likeFilm(7L, 2L);
+ filmService.likeFilm(8L, 3L);
+ filmService.likeFilm(6L, 4L);
+ filmService.likeFilm(10L, 5L);
+ filmService.likeFilm(11L, 6L);
+ filmService.likeFilm(12L, 6L);
+ filmService.likeFilm(10L, 1L);
+ filmService.likeFilm(10L, 2L);
+ mockMvc.perform(get("/films/popular"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.length()").value(10));
+ }
+
}
diff --git a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java
index 58319d5..6518009 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java
@@ -1,45 +1,41 @@
package ru.yandex.practicum.filmorate;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParser;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.http.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
import ru.yandex.practicum.filmorate.model.User;
+
import ru.yandex.practicum.filmorate.service.UserService;
import java.time.LocalDate;
-import java.util.Objects;
+import java.util.Arrays;
import java.util.stream.Stream;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@SpringBootTest
+@AutoConfigureMockMvc
public class UserControllerTest {
@Autowired
- private TestRestTemplate restTemplate;
+ private MockMvc mockMvc;
@Autowired
private UserService userService;
- private final HttpHeaders headers = new HttpHeaders();
-
- @Test
- void contextLoads() {
- }
-
- @BeforeEach
- void setUp() {
- headers.set("Content-Type", "application/json");
- userService.clearData();
- }
-
static Stream provideInvalidUserJsonCreate() {
return Stream.of(
"{\n" +
@@ -123,213 +119,289 @@ static Stream provideInvalidUserJsonUpdate() {
);
}
- static Stream provideInvalidUserJsonIdUpdate() {
- return Stream.of(
- "{\n" +
- " \"login\": \"dolore\",\n" +
- " \"name\": \"Nick Name\",\n" +
- " \"email\": \"mail@mail.ru\",\n" +
- " \"birthday\": \"1946-08-20\"\n" +
- "}", // Без Id
+ @BeforeEach
+ void setUp() {
+ userService.createUser(new User(1L, "test@mail.ru", "testlogin1", "testname1", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(2L, "test2@mail.ru", "testlogin2", "testname2", LocalDate.of(1901, 10, 21)));
+ userService.createUser(new User(3L, "test3@mail.ru", "testlogin3", "testname3", LocalDate.of(1900, 12, 25)));
+ userService.createUser(new User(4L, "test4@mail.ru", "testlogin4", "testname4", LocalDate.of(1901, 10, 21)));
+ }
- "{\n" +
- " \"id\": 123,\n" +
- " \"login\": \"dolore\",\n" +
- " \"name\": \"Nick Name\",\n" +
- " \"email\": \"mail@mail.ru\",\n" +
- " \"birthday\": \"1946-08-20\"\n" +
- "}" // Id отсутствует в списке
- );
+ @AfterEach
+ void tearDown() {
+ userService.clearUsersData();
}
@Test
- void getUsers() {
- userService.addUser(new User(1L, "test@mail.ru", "login1", "user1",
- LocalDate.of(1999, 2, 18)));
- userService.addUser(new User(2L, "test2@mail.ru", "login2", "user2",
- LocalDate.of(2001, 5, 25)));
-
- ResponseEntity response = restTemplate.getForEntity("/users", String.class);
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
- JsonElement expectedJson = JsonParser.parseString(
- "[\n" +
- " {\n" +
- " \"id\": 1,\n" +
- " \"email\": \"test@mail.ru\",\n" +
- " \"login\": \"login1\",\n" +
- " \"name\": \"user1\",\n" +
- " \"birthday\": \"1999-02-18\"\n" +
- " },\n" +
- " {\n" +
- " \"id\": 2,\n" +
- " \"email\": \"test2@mail.ru\",\n" +
- " \"login\": \"login2\",\n" +
- " \"name\": \"user2\",\n" +
- " \"birthday\": \"2001-05-25\"\n" +
- " }\n" +
- "]"
- );
- assertEquals(expectedJson, JsonParser.parseString(response.getBody()));
+ void getAllUsers() throws Exception {
+ mockMvc.perform(get("/users"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$[0].id").value(1))
+ .andExpect(jsonPath("$[1].name").value("testname2"))
+ .andExpect(jsonPath("$[2].email").value("test3@mail.ru"))
+ .andExpect(jsonPath("$[3].login").value("testlogin4"));
+ }
+
+ @Test
+ void getUserById() throws Exception {
+ mockMvc.perform(get("/users/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.id").value(1))
+ .andExpect(jsonPath("$.name").value("testname1"));
}
@Test
- void addUser() {
+ void getUnknownUserById() throws Exception {
+ mockMvc.perform(get("/users/200"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.error").value("not found"))
+ .andExpect(jsonPath("$.message").value("Юзер с id 200 не найден"));
+ }
+
+ @Test
+ void addUser() throws Exception {
String json = "{\n" +
" \"login\": \"testlogin\",\n" +
" \"name\": \"Test User\",\n" +
" \"email\": \"mail@mail.ru\",\n" +
" \"birthday\": \"1946-08-20\"\n" +
"}";
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/users", HttpMethod.POST, entity, String.class);
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
- JsonElement expectedJson = JsonParser.parseString(
- "{ \"id\": 1,\n" +
- " \"login\": \"testlogin\",\n" +
- " \"name\": \"Test User\",\n" +
- " \"email\": \"mail@mail.ru\",\n" +
- " \"birthday\": \"1946-08-20\"\n" +
- "}"
- );
- assertEquals(expectedJson, JsonParser.parseString(response.getBody()));
-
- User createdUser = userService.getUsersMap().get(1L);
- assertNotNull(createdUser);
- assertEquals("testlogin", createdUser.getLogin());
- assertEquals("Test User", createdUser.getName());
- assertEquals("mail@mail.ru", createdUser.getEmail());
- assertEquals(LocalDate.of(1946, 8, 20), createdUser.getBirthday());
+ mockMvc.perform(post("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.id").value(5))
+ .andExpect(jsonPath("$.name").value("Test User"));
+
+ assertEquals(userService.getUserById(5L).getLogin(), "testlogin");
}
@Test
- void addUserWithoutName() {
+ void addUserWithoutName() throws Exception {
String json = "{\n" +
" \"login\": \"testlogin\",\n" +
" \"email\": \"mail@mail.ru\",\n" +
" \"birthday\": \"1946-08-20\"\n" +
"}";
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/users", HttpMethod.POST, entity, String.class);
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
-
- JsonElement expectedJson = JsonParser.parseString(
- "{ \"id\": 1,\n" +
- " \"login\": \"testlogin\",\n" +
- " \"name\": \"testlogin\",\n" +
- " \"email\": \"mail@mail.ru\",\n" +
- " \"birthday\": \"1946-08-20\"\n" +
- "}"
- );
- assertEquals(expectedJson, JsonParser.parseString(response.getBody()));
-
- User createdUser = userService.getUsersMap().get(1L);
- assertNotNull(createdUser);
- assertEquals("testlogin", createdUser.getLogin());
- assertEquals("testlogin", createdUser.getName());
- assertEquals("mail@mail.ru", createdUser.getEmail());
- assertEquals(LocalDate.of(1946, 8, 20), createdUser.getBirthday());
+
+ mockMvc.perform(post("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.id").value(5))
+ .andExpect(jsonPath("$.name").value("testlogin"));
+ assertEquals(userService.getUserById(5L).getName(), "testlogin");
}
@Test
- void updateUser() {
- userService.addUser(new User(1L, "test@mail.ru", "login1", "user1",
- LocalDate.of(1999, 2, 18)));
+ void updateUser() throws Exception {
String json = "{\n" +
" \"id\": 1,\n" +
- " \"login\": \"login1Upd\",\n" +
- " \"name\": \"Test User upd\",\n" +
- " \"email\": \"mailupd@mail.ru\",\n" +
+ " \"login\": \"testlogin1upd\",\n" +
+ " \"name\": \"testname1 upd\",\n" +
+ " \"email\": \"testupd@mail.ru\",\n" +
" \"birthday\": \"1978-10-21\"\n" +
"}";
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/users", HttpMethod.PUT, entity, String.class);
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
-
- JsonElement expectedJson = JsonParser.parseString(json);
- assertEquals(expectedJson, JsonParser.parseString(response.getBody()));
-
- User updatedUser = userService.getUsersMap().get(1L);
- assertNotNull(updatedUser);
- assertEquals("login1Upd", updatedUser.getLogin());
- assertEquals("Test User upd", updatedUser.getName());
- assertEquals("mailupd@mail.ru", updatedUser.getEmail());
- assertEquals(LocalDate.of(1978, 10, 21), updatedUser.getBirthday());
+
+ mockMvc.perform(put("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.id").value(1))
+ .andExpect(jsonPath("$.name").value("testname1 upd"))
+ .andExpect(jsonPath("$.email").value("testupd@mail.ru"))
+ .andExpect(jsonPath("$.login").value("testlogin1upd"))
+ .andExpect(jsonPath("$.birthday").value("1978-10-21"));
+ assertEquals("testlogin1upd", userService.getUserById(1L).getLogin());
+ assertEquals("testname1 upd", userService.getUserById(1L).getName());
+ assertEquals("testupd@mail.ru", userService.getUserById(1L).getEmail());
+ assertEquals("1978-10-21", userService.getUserById(1L).getBirthday().toString());
}
@Test
- void updateUserWithoutName() {
- userService.addUser(new User(1L, "test@mail.ru", "login1", "user1",
- LocalDate.of(1999, 2, 18)));
+ void updateUserWithoutName() throws Exception {
String json = "{\n" +
" \"id\": 1,\n" +
- " \"login\": \"login1Upd\",\n" +
- " \"email\": \"mailupd@mail.ru\",\n" +
+ " \"login\": \"testlogin1upd\",\n" +
+ " \"email\": \"testupd@mail.ru\",\n" +
" \"birthday\": \"1978-10-21\"\n" +
"}";
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/users", HttpMethod.PUT, entity, String.class);
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
-
- User updatedUser = userService.getUsersMap().get(1L);
- assertNotNull(updatedUser);
- assertEquals("login1Upd", updatedUser.getLogin());
- assertEquals("login1Upd", updatedUser.getName());
- assertEquals("mailupd@mail.ru", updatedUser.getEmail());
- assertEquals(LocalDate.of(1978, 10, 21), updatedUser.getBirthday());
+
+ mockMvc.perform(put("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.id").value(1))
+ .andExpect(jsonPath("$.name").value("testlogin1upd"))
+ .andExpect(jsonPath("$.email").value("testupd@mail.ru"))
+ .andExpect(jsonPath("$.login").value("testlogin1upd"))
+ .andExpect(jsonPath("$.birthday").value("1978-10-21"));
+ assertEquals("testlogin1upd", userService.getUserById(1L).getLogin());
+ assertEquals("testlogin1upd", userService.getUserById(1L).getName());
+ assertEquals("testupd@mail.ru", userService.getUserById(1L).getEmail());
+ assertEquals("1978-10-21", userService.getUserById(1L).getBirthday().toString());
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideInvalidUserJsonUpdate")
+ void updateUserValidation(String json) throws Exception {
+ mockMvc.perform(put("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
+
}
@ParameterizedTest
@MethodSource("provideInvalidUserJsonCreate")
- void addUserValidation(String json) {
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/users", HttpMethod.POST, entity, String.class);
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Bad Request\""));
+ void addUserValidation(String json) throws Exception {
+ mockMvc.perform(post("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
+
}
@Test
- void addUserEmptyJson() {
- HttpEntity entity = new HttpEntity<>(null, headers);
- ResponseEntity response = restTemplate.exchange("/users", HttpMethod.POST, entity, String.class);
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Bad Request\""));
+ void addUserEmptyJson() throws Exception {
+ String json = "{}";
+
+ mockMvc.perform(post("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
}
- @ParameterizedTest
- @MethodSource("provideInvalidUserJsonUpdate")
- void updateUserValidation(String json) {
- userService.addUser(new User(1L, "test@mail.ru", "login1", "user1",
- LocalDate.of(1999, 2, 18)));
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/users", HttpMethod.PUT, entity, String.class);
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Bad Request\""));
+ @Test
+ void updateUserWithoutId() throws Exception {
+ String json = "{\n" +
+ " \"login\": \"dolore\",\n" +
+ " \"name\": \"Nick Name\",\n" +
+ " \"email\": \"mail@mail.ru\",\n" +
+ " \"birthday\": \"1946-08-20\"\n" +
+ "}";
+
+ mockMvc.perform(put("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
}
- @ParameterizedTest
- @MethodSource("provideInvalidUserJsonIdUpdate")
- void updateUserIdValidation(String json) {
- userService.addUser(new User(1L, "test@mail.ru", "login1", "user1",
- LocalDate.of(1999, 2, 18)));
- HttpEntity entity = new HttpEntity<>(json, headers);
- ResponseEntity response = restTemplate.exchange("/users", HttpMethod.PUT, entity, String.class);
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Internal Server Error\""));
+ @Test
+ void updateUnknownUser() throws Exception {
+ String json = "{\n" +
+ " \"id\": 123,\n" +
+ " \"login\": \"dolore\",\n" +
+ " \"name\": \"Nick Name\",\n" +
+ " \"email\": \"mail@mail.ru\",\n" +
+ " \"birthday\": \"1946-08-20\"\n" +
+ "}";
+
+ mockMvc.perform(put("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.error").value("not found"))
+ .andExpect(jsonPath("$.message").value("Пользователь с id 123 не найден"));
+ }
+
+ @Test
+ void updateUserEmptyJson() throws Exception {
+ String json = "{}";
+
+ mockMvc.perform(put("/users")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(json))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.error").value("validation error"));
}
@Test
- void updateUserEmptyJson() {
- userService.addUser(new User(1L, "test@mail.ru", "login1", "user1",
- LocalDate.of(1999, 2, 18)));
- HttpEntity entity = new HttpEntity<>(null, headers);
- ResponseEntity response = restTemplate.exchange("/users", HttpMethod.PUT, entity, String.class);
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("\"error\":\"Bad Request\""));
+ void addFriend() throws Exception {
+ mockMvc.perform(put("/users/1/friends/2"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("success"));
+
+ mockMvc.perform(put("/users/1/friends/3"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("success"));
+
+ assertEquals(2, userService.getUserById(1L).getFriends().size());
+ assertEquals(1, userService.getUserById(2L).getFriends().size());
+ assertEquals(1, userService.getUserById(3L).getFriends().size());
+ assertEquals(Arrays.toString(new int[]{2, 3}), userService.getUserById(1L).getFriends().toString());
}
+ @Test
+ void removeFriend() throws Exception {
+ userService.addFriend(1L, 2L);
+ userService.addFriend(1L, 3L);
+
+ mockMvc.perform(delete("/users/1/friends/2"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("success"));
+
+ mockMvc.perform(delete("/users/1/friends/3"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.status").value("success"));
+
+ assertEquals(0, userService.getUserById(1L).getFriends().size());
+ assertEquals(0, userService.getUserById(2L).getFriends().size());
+ assertEquals(0, userService.getUserById(3L).getFriends().size());
+ }
+
+ @Test
+ void addUnknownFriend() throws Exception {
+ mockMvc.perform(put("/users/1/friends/10"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.message").value("Юзер с id 10 не найден"));
+ }
+
+ @Test
+ void addFriendMyself() throws Exception {
+ mockMvc.perform(put("/users/1/friends/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.message").value("Пользователь не может " +
+ "добавить сам себя в друзья"));
+ }
+
+ @Test
+ void addFriendUserFriend() throws Exception {
+ userService.addFriend(1L, 2L);
+
+ mockMvc.perform(put("/users/1/friends/2"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.message").value("Пользователи уже являются друзьями"));
+ }
+
+ @Test
+ void getUserFriends() throws Exception {
+ userService.addFriend(1L, 2L);
+ userService.addFriend(1L, 3L);
+
+ mockMvc.perform(get("/users/1/friends"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.length()").value(2))
+ .andExpect(jsonPath("$[0].id").value(2))
+ .andExpect(jsonPath("$[1].name").value("testname3"));
+ }
+
+ @Test
+ void getCommonUserFriends() throws Exception {
+ userService.addFriend(1L, 2L);
+ userService.addFriend(1L, 3L);
+ userService.addFriend(4L, 2L);
+ userService.addFriend(4L, 3L);
+ mockMvc.perform(get("/users/1/friends/common/4"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.length()").value(2))
+ .andExpect(jsonPath("$[0].id").value(2))
+ .andExpect(jsonPath("$[1].name").value("testname3"));
+ }
+
+
}