diff --git a/README.md b/README.md
index 2cf454a..c1f5a5f 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,5 @@
# java-filmorate
Template repository for Filmorate project.
+
+### Database scheme
+
\ No newline at end of file
diff --git a/database_scheme.png b/database_scheme.png
new file mode 100644
index 0000000..fffc276
Binary files /dev/null and b/database_scheme.png differ
diff --git a/pom.xml b/pom.xml
index 383688d..5bffe1a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,6 @@
org.springframework.boot
spring-boot-starter-web
-
org.projectlombok
lombok
@@ -42,15 +41,42 @@
logbook-spring-boot-starter
3.7.2
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+ runtime
+
-
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ 3.3.1
+
+ checkstyle.xml
+
+
+
+
+ check
+
+ compile
+
+
+
org.springframework.boot
spring-boot-maven-plugin
-
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 0e16103..4c0b29a 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
@@ -5,7 +5,9 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.dto.film.FilmDto;
+import ru.yandex.practicum.filmorate.dto.film.NewFilmRequest;
+import ru.yandex.practicum.filmorate.dto.film.UpdateFilmRequest;
import ru.yandex.practicum.filmorate.service.FilmService;
import java.util.List;
@@ -23,7 +25,7 @@ public FilmController(FilmService filmService) {
* Возвращает фильм по id
*/
@GetMapping("/{id}")
- public ResponseEntity getFilmById(@PathVariable int id) {
+ public ResponseEntity getFilmById(@PathVariable int id) {
return ResponseEntity.ok(filmService.getFilmById(id));
}
@@ -31,32 +33,30 @@ public ResponseEntity getFilmById(@PathVariable int id) {
* Возвращает все фильмы в виде списка
*/
@GetMapping
- public ResponseEntity> getFilms() {
+ public ResponseEntity> getFilms() {
return ResponseEntity.ok(filmService.getFilms());
}
/**
* Добавляет новый фильм.
*
- * @param newFilm объект фильма, который нужно добавить
+ * @param newFilmDto объект фильма, который нужно добавить
* @return ответ, содержащий созданный фильм с присвоенным ID
*/
@PostMapping
- public ResponseEntity addFilm(@Valid @RequestBody Film newFilm) {
- Film createdFilm = filmService.addFilm(newFilm);
- return ResponseEntity.status(HttpStatus.CREATED).body(createdFilm);
+ public ResponseEntity addFilm(@Valid @RequestBody NewFilmRequest newFilmDto) {
+ return ResponseEntity.status(HttpStatus.CREATED).body(filmService.addFilm(newFilmDto));
}
/**
* Обновляет фильм.
*
- * @param updatedFilm объект фильма, который нужно обновить
+ * @param updatedFilmDto объект фильма, который нужно обновить
* @return ответ, содержащий обновлённый фильм
*/
@PutMapping
- public ResponseEntity updateFilm(@Valid @RequestBody Film updatedFilm) {
- Film savedFilm = filmService.updateFilm(updatedFilm);
- return ResponseEntity.ok(savedFilm);
+ public ResponseEntity updateFilm(@Valid @RequestBody UpdateFilmRequest updatedFilmDto) {
+ return ResponseEntity.ok(filmService.updateFilm(updatedFilmDto));
}
/**
@@ -92,7 +92,7 @@ public ResponseEntity removeLikeByUser(@PathVariable int id, @PathVariable
* @return список самых популярных фильмов
*/
@GetMapping("/popular")
- public ResponseEntity> getMostPopularFilms(
+ public ResponseEntity> getMostPopularFilms(
@RequestParam(required = false, defaultValue = "10") int count) {
return ResponseEntity.ok(filmService.getMostPopularFilms(count));
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java
new file mode 100644
index 0000000..b7efcc3
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java
@@ -0,0 +1,39 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import ru.yandex.practicum.filmorate.dto.GenreDto;
+import ru.yandex.practicum.filmorate.service.GenreService;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/genres")
+public class GenreController {
+ private final GenreService genreService;
+
+ @Autowired
+ public GenreController(GenreService genreService) {
+ this.genreService = genreService;
+ }
+
+ /**
+ * Возвращает жанр по id
+ */
+ @GetMapping("/{id}")
+ public ResponseEntity getGenreById(@PathVariable int id) {
+ return ResponseEntity.ok(genreService.getGenreById(id));
+ }
+
+ /**
+ * Возвращает все жанры в виде списка
+ */
+ @GetMapping
+ public ResponseEntity> getGenres() {
+ return ResponseEntity.ok(genreService.getGenres());
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java
new file mode 100644
index 0000000..d87736f
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java
@@ -0,0 +1,36 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.filmorate.dto.MpaDto;
+import ru.yandex.practicum.filmorate.service.MpaService;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/mpa")
+public class MpaController {
+ private final MpaService mpaService;
+
+ @Autowired
+ public MpaController(MpaService mpaService) {
+ this.mpaService = mpaService;
+ }
+
+ /**
+ * Возвращает рейтинг MPA по id
+ */
+ @GetMapping("/{id}")
+ public ResponseEntity getMpaById(@PathVariable int id) {
+ return ResponseEntity.ok(mpaService.getMpaById(id));
+ }
+
+ /**
+ * Возвращает все рейтинги MPA
+ */
+ @GetMapping
+ public ResponseEntity> getMpaList() {
+ return ResponseEntity.ok(mpaService.getMpaList());
+ }
+}
\ No newline at end of file
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 a441f3a..c4b41ae 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
@@ -5,7 +5,9 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
-import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.dto.user.NewUserRequest;
+import ru.yandex.practicum.filmorate.dto.user.UpdateUserRequest;
+import ru.yandex.practicum.filmorate.dto.user.UserDto;
import ru.yandex.practicum.filmorate.service.UserService;
import java.util.List;
@@ -23,7 +25,7 @@ public UserController(UserService userService) {
* Возвращает пользователя по id
*/
@GetMapping("/{id}")
- public ResponseEntity getUserById(@PathVariable int id) {
+ public ResponseEntity getUserById(@PathVariable int id) {
return ResponseEntity.ok(userService.getUserById(id));
}
@@ -31,7 +33,7 @@ public ResponseEntity getUserById(@PathVariable int id) {
* Возвращает всех пользователей в виде списка
*/
@GetMapping
- public ResponseEntity> getUsers() {
+ public ResponseEntity> getUsers() {
return ResponseEntity.ok(userService.getUsers());
}
@@ -42,9 +44,8 @@ public ResponseEntity> getUsers() {
* @return ответ, содержащий созданного пользователя с присвоенным ID
*/
@PostMapping
- public ResponseEntity addUser(@Valid @RequestBody User newUser) {
- User createdUser = userService.addUser(newUser);
- return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
+ public ResponseEntity addUser(@Valid @RequestBody NewUserRequest newUser) {
+ return ResponseEntity.status(HttpStatus.CREATED).body(userService.addUser(newUser));
}
/**
@@ -54,9 +55,8 @@ public ResponseEntity addUser(@Valid @RequestBody User newUser) {
* @return ответ, содержащий обновлённого пользователя
*/
@PutMapping
- public ResponseEntity updateUser(@Valid @RequestBody User updatedUser) {
- User savedUser = userService.updateUser(updatedUser);
- return ResponseEntity.ok(savedUser);
+ public ResponseEntity updateUser(@Valid @RequestBody UpdateUserRequest updatedUser) {
+ return ResponseEntity.ok(userService.updateUser(updatedUser));
}
/**
@@ -92,7 +92,7 @@ public ResponseEntity removeFriend(@PathVariable int id, @PathVariable int
* @return список друзей-пользователей указанного пользователя.
*/
@GetMapping("/{id}/friends")
- public ResponseEntity> getAllFriends(@PathVariable int id) {
+ public ResponseEntity> getAllFriends(@PathVariable int id) {
return ResponseEntity.ok(userService.getUserFriendsById(id));
}
@@ -104,7 +104,7 @@ public ResponseEntity> getAllFriends(@PathVariable int id) {
* @return список общих друзей в виде списка пользователей.
*/
@GetMapping("/{id}/friends/common/{otherId}")
- public ResponseEntity> getCommonFriends(@PathVariable int id, @PathVariable int otherId) {
+ public ResponseEntity> getCommonFriends(@PathVariable int id, @PathVariable int otherId) {
return ResponseEntity.ok(userService.getCommonFriends(id, otherId));
}
}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/GenreDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/GenreDto.java
new file mode 100644
index 0000000..67b8ad9
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dto/GenreDto.java
@@ -0,0 +1,11 @@
+package ru.yandex.practicum.filmorate.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class GenreDto {
+ private Integer id;
+ private String name;
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/MpaDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/MpaDto.java
new file mode 100644
index 0000000..d0faa73
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dto/MpaDto.java
@@ -0,0 +1,11 @@
+package ru.yandex.practicum.filmorate.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class MpaDto {
+ private Integer id;
+ private String name;
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/film/FilmDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/film/FilmDto.java
new file mode 100644
index 0000000..16fa38b
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dto/film/FilmDto.java
@@ -0,0 +1,23 @@
+package ru.yandex.practicum.filmorate.dto.film;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+import java.time.LocalDate;
+import java.util.Set;
+
+@Data
+@NoArgsConstructor
+public class FilmDto {
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ private int id;
+ private String name;
+ private String description;
+ private LocalDate releaseDate;
+ private Integer duration;
+ private Set genres;
+ private Mpa mpa;
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/film/NewFilmRequest.java b/src/main/java/ru/yandex/practicum/filmorate/dto/film/NewFilmRequest.java
new file mode 100644
index 0000000..1b499a9
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dto/film/NewFilmRequest.java
@@ -0,0 +1,24 @@
+package ru.yandex.practicum.filmorate.dto.film;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+import java.time.LocalDate;
+import java.util.Set;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class NewFilmRequest {
+ private String name;
+ private String description;
+ private LocalDate releaseDate;
+ private Integer duration;
+ private Set genres;
+ private Mpa mpa;
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/film/UpdateFilmRequest.java b/src/main/java/ru/yandex/practicum/filmorate/dto/film/UpdateFilmRequest.java
new file mode 100644
index 0000000..da3f4e4
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dto/film/UpdateFilmRequest.java
@@ -0,0 +1,49 @@
+package ru.yandex.practicum.filmorate.dto.film;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+import java.time.LocalDate;
+import java.util.Set;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UpdateFilmRequest {
+ private int id;
+ private String name;
+ private String description;
+ private LocalDate releaseDate;
+ private Integer duration;
+ private Set genres;
+ private Mpa mpa;
+
+ public boolean hasName() {
+ return !(name == null || name.isBlank());
+ }
+
+ public boolean hasDescription() {
+ return !(description == null || description.isBlank());
+ }
+
+ public boolean hasReleaseDate() {
+ return !(releaseDate == null);
+ }
+
+ public boolean hasDuration() {
+ return !(duration == null);
+ }
+
+ public boolean hasGenres() {
+ return !(genres == null || genres.isEmpty());
+ }
+
+ public boolean hasMpaRating() {
+ return !(mpa == null);
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/user/NewUserRequest.java b/src/main/java/ru/yandex/practicum/filmorate/dto/user/NewUserRequest.java
new file mode 100644
index 0000000..d360111
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dto/user/NewUserRequest.java
@@ -0,0 +1,19 @@
+package ru.yandex.practicum.filmorate.dto.user;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class NewUserRequest {
+ private String name;
+ private String email;
+ private String login;
+ private LocalDate birthday;
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/user/UpdateUserRequest.java b/src/main/java/ru/yandex/practicum/filmorate/dto/user/UpdateUserRequest.java
new file mode 100644
index 0000000..d5080a5
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dto/user/UpdateUserRequest.java
@@ -0,0 +1,35 @@
+package ru.yandex.practicum.filmorate.dto.user;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import java.time.LocalDate;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UpdateUserRequest {
+ int id;
+ private String name;
+ private String email;
+ private String login;
+ private LocalDate birthday;
+
+ public boolean hasLogin() {
+ return ! (login == null || login.isBlank());
+ }
+
+ public boolean hasName() {
+ return ! (name == null || name.isBlank());
+ }
+
+ public boolean hasEmail() {
+ return ! (email == null || email.isBlank());
+ }
+
+ public boolean hasBirthday() {
+ return ! (birthday == null);
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/dto/user/UserDto.java b/src/main/java/ru/yandex/practicum/filmorate/dto/user/UserDto.java
new file mode 100644
index 0000000..fdab327
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/dto/user/UserDto.java
@@ -0,0 +1,16 @@
+package ru.yandex.practicum.filmorate.dto.user;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+@Data
+@NoArgsConstructor
+public class UserDto {
+ private int id;
+ private String name;
+ private String email;
+ private String login;
+ private LocalDate birthday;
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/InternalServerException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/InternalServerException.java
new file mode 100644
index 0000000..c9eba3a
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/exception/InternalServerException.java
@@ -0,0 +1,7 @@
+package ru.yandex.practicum.filmorate.exception;
+
+public class InternalServerException extends RuntimeException {
+ public InternalServerException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/FilmMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/FilmMapper.java
new file mode 100644
index 0000000..dadcf11
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/FilmMapper.java
@@ -0,0 +1,73 @@
+package ru.yandex.practicum.filmorate.mapper;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import ru.yandex.practicum.filmorate.dto.film.FilmDto;
+import ru.yandex.practicum.filmorate.dto.film.NewFilmRequest;
+import ru.yandex.practicum.filmorate.dto.film.UpdateFilmRequest;
+import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+import java.time.LocalDate;
+import java.util.Set;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class FilmMapper {
+ public static Film mapToFilm(NewFilmRequest request) {
+ String name = request.getName();
+ String description = request.getDescription();
+ LocalDate releaseDate = request.getReleaseDate();
+ Integer duration = request.getDuration();
+ Set genres = request.getGenres();
+ Mpa mpaRatingId = request.getMpa();
+
+ return Film.builder()
+ .name(name)
+ .description(description)
+ .releaseDate(releaseDate)
+ .duration(duration)
+ .genres(genres)
+ .mpa(mpaRatingId)
+ .build();
+ }
+
+ public static FilmDto mapToFilmDto(Film film) {
+ FilmDto dto = new FilmDto();
+ dto.setId(film.getId());
+ dto.setName(film.getName());
+ dto.setDescription(film.getDescription());
+ dto.setReleaseDate(film.getReleaseDate());
+ dto.setDuration(film.getDuration());
+ dto.setGenres(film.getGenres());
+ dto.setMpa(film.getMpa());
+ return dto;
+ }
+
+ public static Film updateFilmFields(Film film, UpdateFilmRequest request) {
+ if (request.hasName()) {
+ film.setName(request.getName());
+ }
+
+ if (request.hasDescription()) {
+ film.setDescription(request.getDescription());
+ }
+
+ if (request.hasDuration()) {
+ film.setDuration(request.getDuration());
+ }
+
+ if (request.hasReleaseDate()) {
+ film.setReleaseDate(request.getReleaseDate());
+ }
+
+ if (request.hasGenres()) {
+ film.setGenres(request.getGenres());
+ }
+
+ if (request.hasMpaRating()) {
+ film.setMpa(request.getMpa());
+ }
+ return film;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/GenreMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/GenreMapper.java
new file mode 100644
index 0000000..2bd0ca5
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/GenreMapper.java
@@ -0,0 +1,20 @@
+package ru.yandex.practicum.filmorate.mapper;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import ru.yandex.practicum.filmorate.dto.GenreDto;
+import ru.yandex.practicum.filmorate.model.Genre;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class GenreMapper {
+ public static Genre mapToGenre(GenreDto request) {
+ return new Genre(request.getId(), request.getName());
+ }
+
+ public static GenreDto mapToGenreDto(Genre genre) {
+ GenreDto dto = new GenreDto();
+ dto.setId(genre.getId());
+ dto.setName(genre.getName());
+ return dto;
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/MpaMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/MpaMapper.java
new file mode 100644
index 0000000..193a41f
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/MpaMapper.java
@@ -0,0 +1,20 @@
+package ru.yandex.practicum.filmorate.mapper;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import ru.yandex.practicum.filmorate.dto.MpaDto;
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class MpaMapper {
+ public static Mpa mapToMpa(MpaDto request) {
+ return new Mpa(request.getId(), request.getName());
+ }
+
+ public static MpaDto mapToMpaDto(Mpa mpa) {
+ MpaDto dto = new MpaDto();
+ dto.setId(mpa.getId());
+ dto.setName(mpa.getName());
+ return dto;
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/mapper/UserMapper.java b/src/main/java/ru/yandex/practicum/filmorate/mapper/UserMapper.java
new file mode 100644
index 0000000..3d5ec7f
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/mapper/UserMapper.java
@@ -0,0 +1,57 @@
+package ru.yandex.practicum.filmorate.mapper;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import ru.yandex.practicum.filmorate.dto.user.NewUserRequest;
+import ru.yandex.practicum.filmorate.dto.user.UpdateUserRequest;
+import ru.yandex.practicum.filmorate.dto.user.UserDto;
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.time.LocalDate;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class UserMapper {
+ public static User mapToUser(NewUserRequest request) {
+ String name = request.getName();
+ String email = request.getEmail();
+ String login = request.getLogin();
+ LocalDate birthday = request.getBirthday();
+
+ return User.builder()
+ .name(name)
+ .email(email)
+ .login(login)
+ .birthday(birthday)
+ .build();
+ }
+
+ public static UserDto mapToUserDto(User user) {
+ UserDto dto = new UserDto();
+ dto.setId(user.getId());
+ dto.setName(user.getName());
+ dto.setEmail(user.getEmail());
+ dto.setLogin(user.getLogin());
+ dto.setBirthday(user.getBirthday());
+ return dto;
+ }
+
+ public static User updateUserFields(User user, UpdateUserRequest request) {
+ if (request.hasLogin()) {
+ user.setLogin(request.getLogin());
+ }
+
+ if (request.hasName()) {
+ user.setName(request.getName());
+ }
+
+ if (request.hasEmail()) {
+ user.setEmail(request.getEmail());
+ }
+
+ if (request.hasBirthday()) {
+ user.setBirthday(request.getBirthday());
+ }
+
+ return user;
+ }
+}
\ No newline at end of file
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 e9b9a17..dc918a2 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
@@ -27,4 +27,6 @@ public class Film {
private Integer duration;
private Set likes;
+ private Set genres;
+ private Mpa mpa;
}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java
new file mode 100644
index 0000000..137f4b0
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java
@@ -0,0 +1,13 @@
+package ru.yandex.practicum.filmorate.model;
+
+import lombok.*;
+
+@Data
+@Builder(toBuilder = true)
+@EqualsAndHashCode(of = { "id" })
+@AllArgsConstructor
+@NoArgsConstructor
+public class Genre {
+ private Integer id;
+ private String name;
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java
new file mode 100644
index 0000000..04b9dd9
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java
@@ -0,0 +1,13 @@
+package ru.yandex.practicum.filmorate.model;
+
+import lombok.*;
+
+@Data
+@Builder(toBuilder = true)
+@EqualsAndHashCode(of = { "id" })
+@AllArgsConstructor
+@NoArgsConstructor
+public class Mpa {
+ private Integer id;
+ private String name;
+}
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 5fd80e8..4a77c66 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
@@ -5,14 +5,17 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.dto.film.FilmDto;
+import ru.yandex.practicum.filmorate.dto.film.NewFilmRequest;
+import ru.yandex.practicum.filmorate.dto.film.UpdateFilmRequest;
import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.mapper.FilmMapper;
import ru.yandex.practicum.filmorate.model.Film;
import ru.yandex.practicum.filmorate.storage.FilmStorage;
import ru.yandex.practicum.filmorate.storage.UserStorage;
import java.time.LocalDate;
import java.time.Month;
-import java.util.Comparator;
import java.util.List;
@Service
@@ -33,16 +36,16 @@ public FilmService(FilmStorage filmStorage, UserStorage userStorage) {
* Возвращает фильм по id.
* Вызывает метод хранилища по получению фильма по id.
*/
- public Film getFilmById(int id) {
- return filmStorage.getFilmById(id);
+ public FilmDto getFilmById(int id) {
+ return FilmMapper.mapToFilmDto(filmStorage.getFilmById(id));
}
/**
* Возвращает все фильмы в виде списка.
* Вызывает метод хранилища по получению всех фильмов
*/
- public List getFilms() {
- return filmStorage.getFilms();
+ public List getFilms() {
+ return filmStorage.getFilms().stream().map(FilmMapper::mapToFilmDto).toList();
}
/**
@@ -50,7 +53,8 @@ public List getFilms() {
* Проверяет поля переданного фильма на соответствие.
* Если всё хорошо, то вызывает соответствующий метод хранилища.
*/
- public Film addFilm(Film newFilm) {
+ public FilmDto addFilm(NewFilmRequest newFilmDto) {
+ Film newFilm = FilmMapper.mapToFilm(newFilmDto);
try {
checkIsValidFilm(newFilm);
} catch (ValidationException exception) {
@@ -58,7 +62,7 @@ public Film addFilm(Film newFilm) {
throw exception;
}
log.trace("Данные фильма {} прошли валидацию при добавлении", newFilm.getId());
- return filmStorage.addFilm(newFilm);
+ return FilmMapper.mapToFilmDto(filmStorage.addFilm(newFilm));
}
/**
@@ -66,7 +70,8 @@ public Film addFilm(Film newFilm) {
* Проверяет поля переданного фильма на соответствие.
* Если всё хорошо, то вызывает соответствующий метод хранилища.
*/
- public Film updateFilm(Film updatedFilm) {
+ public FilmDto updateFilm(UpdateFilmRequest updatedFilmDto) {
+ Film updatedFilm = FilmMapper.updateFilmFields(filmStorage.getFilmById(updatedFilmDto.getId()), updatedFilmDto);
try {
checkIsValidFilm(updatedFilm);
} catch (ValidationException exception) {
@@ -75,7 +80,7 @@ public Film updateFilm(Film updatedFilm) {
throw exception;
}
log.trace("Фильм {} прошёл валидацию для обновления", updatedFilm.getId());
- return filmStorage.updateFilm(updatedFilm);
+ return FilmMapper.mapToFilmDto(filmStorage.updateFilm(updatedFilm));
}
/**
@@ -86,13 +91,11 @@ public Film updateFilm(Film updatedFilm) {
public void addLike(int filmId, int userId) {
userStorage.getUserById(userId);
log.trace("Пользователь {} найден для добавления лайка", userId);
- Film film = filmStorage.getFilmById(filmId);
+ filmStorage.getFilmById(filmId);
log.trace("Фильм {} найден для добавления лайка", filmId);
- film.getLikes().add(userId);
+ filmStorage.addLike(filmId, userId);
log.info("Добавление лайка от пользователя {} для фильма {} выполнено", userId, filmId);
-
- filmStorage.updateFilm(film);
}
/**
@@ -106,22 +109,16 @@ public void removeLike(int filmId, int userId) {
Film film = filmStorage.getFilmById(filmId);
log.trace("Фильм {} найден для удаления лайка", filmId);
- film.getLikes().remove(userId);
+ filmStorage.removeLike(filmId, userId);
log.info("Удаление лайка от пользователя {} для фильма {} выполнено", userId, filmId);
-
- filmStorage.updateFilm(film);
}
/**
* Возвращает список самых популярных фильмов в виде списка.
* Вызывает метод хранилища по получению всех фильмов, сортирует их и фильтрует по количеству.
*/
- public List getMostPopularFilms(int count) {
- return filmStorage.getFilms().stream()
- .sorted(Comparator.comparingInt(
- (Film film) -> film.getLikes().size()).reversed().thenComparingInt(Film::getId))
- .limit(count)
- .toList();
+ public List getMostPopularFilms(int count) {
+ return filmStorage.getMostPopularFilms(count).stream().map(FilmMapper::mapToFilmDto).toList();
}
/**
@@ -133,6 +130,10 @@ private void checkIsValidFilm(Film film) throws ValidationException {
throw new ValidationException("Фильм для валидации входных параметров не найден");
}
+ if (film.getName().isBlank()) {
+ throw new ValidationException("Название фильма не может быть пустым");
+ }
+
if (film.getDescription().length() > FILM_DESCRIPTION_LENGTH) {
throw new ValidationException("Описание фильма не может быть больше 200 символов");
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java
new file mode 100644
index 0000000..6c0e748
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java
@@ -0,0 +1,33 @@
+package ru.yandex.practicum.filmorate.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.dto.GenreDto;
+import ru.yandex.practicum.filmorate.mapper.GenreMapper;
+import ru.yandex.practicum.filmorate.storage.GenreStorage;
+
+import java.util.List;
+
+@Service
+public class GenreService {
+ private final GenreStorage genreStorage;
+
+ @Autowired
+ public GenreService(GenreStorage genreStorage) {
+ this.genreStorage = genreStorage;
+ }
+
+ /**
+ * Возвращает жанр по id.
+ */
+ public GenreDto getGenreById(int id) {
+ return GenreMapper.mapToGenreDto(genreStorage.getGenreById(id));
+ }
+
+ /**
+ * Возвращает всех жанры в виде списка.
+ */
+ public List getGenres() {
+ return genreStorage.getGenres().stream().map(GenreMapper::mapToGenreDto).toList();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java
new file mode 100644
index 0000000..4d41d41
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java
@@ -0,0 +1,33 @@
+package ru.yandex.practicum.filmorate.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.dto.MpaDto;
+import ru.yandex.practicum.filmorate.mapper.MpaMapper;
+import ru.yandex.practicum.filmorate.storage.MpaStorage;
+
+import java.util.List;
+
+@Service
+public class MpaService {
+ private final MpaStorage mpaStorage;
+
+ @Autowired
+ public MpaService(MpaStorage mpaStorage) {
+ this.mpaStorage = mpaStorage;
+ }
+
+ /**
+ * Возвращает MPA рейтинг по id.
+ */
+ public MpaDto getMpaById(int id) {
+ return MpaMapper.mapToMpaDto(mpaStorage.getMpaById(id));
+ }
+
+ /**
+ * Возвращает всех MPA рейтинги в виде списка.
+ */
+ public List getMpaList() {
+ return mpaStorage.getMpaList().stream().map(MpaMapper::mapToMpaDto).toList();
+ }
+}
\ No newline at end of file
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 5ef5d21..b7b3a60 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
@@ -4,8 +4,12 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.dto.user.NewUserRequest;
+import ru.yandex.practicum.filmorate.dto.user.UpdateUserRequest;
+import ru.yandex.practicum.filmorate.dto.user.UserDto;
import ru.yandex.practicum.filmorate.exception.NotFoundException;
import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.mapper.UserMapper;
import ru.yandex.practicum.filmorate.model.User;
import ru.yandex.practicum.filmorate.storage.UserStorage;
@@ -26,16 +30,16 @@ public UserService(UserStorage userStorage) {
* Возвращает пользователя по id.
* Вызывает метод хранилища по получению пользователя по id.
*/
- public User getUserById(int id) {
- return userStorage.getUserById(id);
+ public UserDto getUserById(int id) {
+ return UserMapper.mapToUserDto(userStorage.getUserById(id));
}
/**
* Возвращает всех пользователей в виде списка.
* Вызывает соответствующий метод хранилища.
*/
- public List getUsers() {
- return userStorage.getUsers();
+ public List getUsers() {
+ return userStorage.getUsers().stream().map(UserMapper::mapToUserDto).toList();
}
/**
@@ -46,7 +50,8 @@ public List getUsers() {
* @param newUser объект пользователя, который нужно добавить
* @return созданный пользователь с присвоенным ID
*/
- public User addUser(User newUser) {
+ public UserDto addUser(NewUserRequest newUserDto) {
+ User newUser = UserMapper.mapToUser(newUserDto);
try {
checkIsValidUser(newUser);
} catch (ValidationException exception) {
@@ -55,7 +60,7 @@ public User addUser(User newUser) {
throw exception;
}
log.trace("Данные новго пользователя c логином {} прошли валидацию при добавлении", newUser.getLogin());
- return userStorage.addUser(newUser);
+ return UserMapper.mapToUserDto(userStorage.addUser(newUser));
}
/**
@@ -66,7 +71,10 @@ public User addUser(User newUser) {
* @param updatedUser объект пользователя, который нужно обновить
* @return обновлённый пользователь
*/
- public User updateUser(User updatedUser) {
+ public UserDto updateUser(UpdateUserRequest updatedUserDto) {
+ User updatedUser = userStorage.getUserById(updatedUserDto.getId());
+ updatedUser = UserMapper.updateUserFields(updatedUser, updatedUserDto);
+
try {
checkIsValidUser(updatedUser);
} catch (ValidationException exception) {
@@ -76,7 +84,7 @@ public User updateUser(User updatedUser) {
}
log.info("Данные пользователя {} прошли валидацию при обновлении", updatedUser.getId());
- return userStorage.updateUser(updatedUser);
+ return UserMapper.mapToUserDto(userStorage.updateUser(updatedUser));
}
/**
@@ -89,13 +97,11 @@ public void addFriends(int firstUserId, int secondUserId) {
User secondUser = userStorage.getUserById(secondUserId);
log.trace("Пользователь {} найден для добавления в друзья", secondUserId);
- firstUser.getFriends().add(secondUserId);
- secondUser.getFriends().add(firstUser.getId());
- log.info("Пользователь {} добавлен в друзья пользователя {}.",
- secondUserId, firstUserId);
+ if (firstUser.getFriends().contains(secondUserId)) {
+ throw new ValidationException("Пользователь уже добавлен в друзья");
+ }
- userStorage.updateUser(firstUser);
- userStorage.updateUser(secondUser);
+ userStorage.addFriends(firstUserId, secondUserId);
log.trace("Пользователи обновлены в хранилище.");
}
@@ -109,13 +115,7 @@ public void removeFriends(int firstUserId, int secondUserId) {
User secondUser = userStorage.getUserById(secondUserId);
log.trace("Пользователь {} найден для удаления мз друзей", secondUserId);
- firstUser.getFriends().remove(secondUserId);
- secondUser.getFriends().remove(firstUserId);
- log.info("Пользователь {} удален из друзей пользователя {}.",
- secondUserId, firstUserId);
-
- userStorage.updateUser(firstUser);
- userStorage.updateUser(secondUser);
+ userStorage.removeFriends(firstUserId, secondUserId);
log.trace("Пользователи обновлены в хранилище.");
}
@@ -123,9 +123,9 @@ public void removeFriends(int firstUserId, int secondUserId) {
* Ищет общих друзей у пользователей
* Если оба пользователя существуют, то возвращает список общих друзей.
*/
- public List getCommonFriends(int firstUserId, int secondUserId) {
- List firstFriends = getUserFriendsById(firstUserId);
- List secondFriends = getUserFriendsById(secondUserId);
+ public List getCommonFriends(int firstUserId, int secondUserId) {
+ List firstFriends = getUserFriendsById(firstUserId);
+ List secondFriends = getUserFriendsById(secondUserId);
log.trace("Списки друзей пользователей для поиска общих друзей составлены", secondUserId);
return firstFriends.stream()
@@ -137,11 +137,14 @@ public List getCommonFriends(int firstUserId, int secondUserId) {
* Возвращает всех друзей пользователя
* Если пользователь существуюет, то возвращает список по id
*/
- public List getUserFriendsById(int userId) {
+ public List getUserFriendsById(int userId) {
User user = userStorage.getUserById(userId);
log.trace("Пользователь {} найден для поиска всех его друзей", userId);
- return user.getFriends().stream().map(id -> userStorage.getUserById(id)).toList();
+ return user.getFriends().stream()
+ .map(id -> userStorage.getUserById(id))
+ .map(UserMapper::mapToUserDto)
+ .toList();
}
/**
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java
index 8ba57f5..7517b35 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java
@@ -23,4 +23,19 @@ public interface FilmStorage {
* Обновляет фильм.
*/
Film updateFilm(Film updatedFilm);
+
+ /**
+ * Добавляет лайк.
+ */
+ void addLike(int filmId, int userId);
+
+ /**
+ * Удаляет лайк.
+ */
+ void removeLike(int filmId, int userId);
+
+ /**
+ * Возвращает популярные фильмы
+ */
+ List getMostPopularFilms(int count);
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java
new file mode 100644
index 0000000..d776e8b
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java
@@ -0,0 +1,16 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import ru.yandex.practicum.filmorate.model.Genre;
+import java.util.List;
+
+public interface GenreStorage {
+ /**
+ * Возвращает жанр по id
+ */
+ Genre getGenreById(int id);
+
+ /**
+ * Возвращает все жанры в виде списка
+ */
+ List getGenres();
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java
index e128d75..38c1f37 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java
@@ -107,4 +107,25 @@ private int getNextId() {
.orElse(0);
return ++currentMaxId;
}
+
+ /**
+ * Добавляет лайк.
+ */
+ public void addLike(int filmId, int userId) {
+ throw new NotFoundException("Метод не поддерживается");
+ }
+
+ /**
+ * Удаляет лайк.
+ */
+ public void removeLike(int filmId, int userId) {
+ throw new NotFoundException("Метод не поддерживается");
+ }
+
+ /**
+ * Возвращает популярные фильмы
+ */
+ public List getMostPopularFilms(int count) {
+ throw new NotFoundException("Метод не поддерживается");
+ }
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java
index 1af6df2..56104a3 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java
@@ -105,4 +105,28 @@ private int getNextId() {
.orElse(0);
return ++currentMaxId;
}
+
+ /**
+ * Заглушка для метода добавления в друзья
+ */
+ @Override
+ public void addFriends(int userId, int friendId) {
+ throw new NotFoundException("Метод не поддерживается");
+ }
+
+ /**
+ * Заглушка для метода удаления из друзей
+ */
+ @Override
+ public void removeFriends(int userId, int friendId) {
+ throw new NotFoundException("Метод не поддерживается");
+ }
+
+ /**
+ * Заглушка для метода получения друзей пользователя в виде списка id
+ */
+ @Override
+ public Set getUserFriends(Integer userId) {
+ throw new NotFoundException("Метод не поддерживается");
+ }
}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java
new file mode 100644
index 0000000..ee7b2f9
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java
@@ -0,0 +1,17 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+import java.util.List;
+
+public interface MpaStorage {
+ /**
+ * Возвращает MPA рейтинг по id
+ */
+ Mpa getMpaById(int id);
+
+ /**
+ * Возвращает все MPA рейтинги в виде списка
+ */
+ List getMpaList();
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java
index 7a01079..f40c5b6 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java
@@ -1,7 +1,9 @@
package ru.yandex.practicum.filmorate.storage;
import ru.yandex.practicum.filmorate.model.User;
+
import java.util.List;
+import java.util.Set;
public interface UserStorage {
/**
@@ -33,4 +35,19 @@ public interface UserStorage {
* @return копия обновлённого пользователя
*/
User updateUser(User updatedUser);
+
+ /**
+ * Добавляет пользователя в друзья
+ */
+ void addFriends(int userId, int friendId);
+
+ /**
+ * Удаляет пользователя из друзей
+ */
+ void removeFriends(int userId, int friendId);
+
+ /**
+ * Возвращает друзей пользователя в виде списка id
+ */
+ Set getUserFriends(Integer userId);
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/BaseStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/BaseStorage.java
new file mode 100644
index 0000000..1a3fa1c
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/BaseStorage.java
@@ -0,0 +1,65 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+import ru.yandex.practicum.filmorate.exception.InternalServerException;
+
+import java.sql.PreparedStatement;
+import java.sql.Statement;
+import java.util.List;
+import java.util.Optional;
+
+@RequiredArgsConstructor
+public class BaseStorage {
+ protected final JdbcTemplate jdbc;
+ protected final RowMapper mapper;
+
+ protected Optional findOne(String query, Object... params) {
+ try {
+ T result = jdbc.queryForObject(query, mapper, params);
+ return Optional.ofNullable(result);
+ } catch (EmptyResultDataAccessException ignored) {
+ return Optional.empty();
+ }
+ }
+
+ protected List findMany(String query, Object... params) {
+ return jdbc.query(query, mapper, params);
+ }
+
+ protected boolean delete(String query, int id) {
+ int rowsDeleted = jdbc.update(query, id);
+ return rowsDeleted > 0;
+ }
+
+ protected void update(String query, Object... params) {
+ int rowsUpdated = jdbc.update(query, params);
+ if (rowsUpdated == 0) {
+ throw new InternalServerException("Не удалось обновить данные");
+ }
+ }
+
+ protected int insert(String query, Object... params) {
+ GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
+ jdbc.update(connection -> {
+ PreparedStatement ps = connection
+ .prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
+ for (int idx = 0; idx < params.length; idx++) {
+ ps.setObject(idx + 1, params[idx]);
+ }
+ return ps;
+ }, keyHolder);
+
+ Integer id = keyHolder.getKeyAs(Integer.class);
+
+ // Возвращаем id нового пользователя
+ if (id != null) {
+ return id;
+ } else {
+ throw new InternalServerException("Не удалось сохранить данные");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/FilmDbStorage.java
new file mode 100644
index 0000000..eab7ab1
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/FilmDbStorage.java
@@ -0,0 +1,271 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Primary;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+import ru.yandex.practicum.filmorate.exception.InternalServerException;
+import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.model.Mpa;
+import ru.yandex.practicum.filmorate.storage.FilmStorage;
+import ru.yandex.practicum.filmorate.storage.GenreStorage;
+import ru.yandex.practicum.filmorate.storage.MpaStorage;
+import ru.yandex.practicum.filmorate.storage.dao.mapper.FilmRowMapper;
+
+import java.util.*;
+
+@Primary
+@Repository
+public class FilmDbStorage extends BaseStorage implements FilmStorage {
+ private final MpaStorage mpaStorage;
+ private final GenreStorage genreStorage;
+
+ private static final Logger log = LoggerFactory.getLogger(FilmDbStorage.class);
+
+ private static final String GET_FILM_BY_ID = "SELECT * FROM films WHERE id = ?;";
+ private static final String GET_FILMS = "SELECT * FROM films;";
+ private static final String ADD_FILM = "INSERT INTO films (name, description, duration, release_date, " +
+ "mpa_rating_id) VALUES (?, ?, ?, ?, ?);";
+ private static final String ADD_FILM_SIMPLE = "INSERT INTO films (name, description, duration, release_date) " +
+ "VALUES (?, ?, ?, ?);";
+ private static final String UPDATE_FILM = "UPDATE films SET name = ?,description = ?, duration = ?, " +
+ "release_date = ?, mpa_rating_id = ? WHERE id = ?;";
+ private static final String UPDATE_FILM_SHORT = "UPDATE films SET name = ?,description = ?, duration = ?, " +
+ "release_date = ? WHERE id = ?;";
+ private static final String GET_POPULAR_FILMS = "SELECT f.*, COUNT(fl.user_id) as likes_count FROM films f " +
+ "LEFT JOIN films_likes fl ON f.id = fl.film_id " +
+ "GROUP BY f.id " +
+ "ORDER BY likes_count DESC " +
+ "LIMIT ?;";
+
+ private static final String GET_GENRES_ID = "SELECT genre_id FROM films_genres WHERE film_id = ?;";
+ private static final String GET_GENRE_NAME = "SELECT name FROM genres WHERE id = ?;";
+ private static final String ADD_GENRE = "INSERT INTO films_genres (film_id, genre_id) " +
+ "VALUES (?, ?);";
+ private static final String DELETE_GENRES = "DELETE FROM films_genres WHERE film_id = ?;";
+
+ private static final String GET_MPA_ID = "SELECT mpa_rating_id FROM films WHERE id = ?;";
+ private static final String GET_MPA_NAME = "SELECT name FROM mpa_ratings WHERE id = ?;";
+
+ private static final String ADD_USER_LIKE = "INSERT INTO films_likes (film_id, user_id) VALUES (?, ?);";
+ private static final String DELETE_USER_LIKE = "DELETE FROM films_likes WHERE film_id = ? " +
+ "AND user_id = ?;";
+
+
+ public FilmDbStorage(JdbcTemplate jdbc, FilmRowMapper mapper, MpaStorage mpaStorage, GenreStorage genreStorage) {
+ super(jdbc, mapper);
+ this.mpaStorage = mpaStorage;
+ this.genreStorage = genreStorage;
+ }
+
+ /**
+ * Возвращает фильм по id из БД
+ */
+ @Override
+ public Film getFilmById(int id) {
+ Film film = findOne(GET_FILM_BY_ID, id).orElseThrow(() -> {
+ String filmNotFound = "Фильм с id = " + id + " не найден";
+ log.error(filmNotFound);
+ return new NotFoundException(filmNotFound);
+ });
+ enrichFilmByAdditionalInfo(film);
+ return film;
+ }
+
+ /**
+ * Возвращает все фильмы из БД в виде списка
+ */
+ @Override
+ public List getFilms() {
+ return findMany(GET_FILMS).stream().peek(this::enrichFilmByAdditionalInfo).toList();
+ }
+
+ /**
+ * Добавляет новый фильм в БД
+ *
+ * @param newFilm объект фильма, который нужно добавить
+ * @return созданный фильм с присвоенным ID
+ */
+ @Override
+ public Film addFilm(Film newFilm) {
+ if (newFilm == null) {
+ String filmNotFound = "Фильм для добавления не найден";
+ log.error(filmNotFound);
+ throw new NotFoundException(filmNotFound);
+ }
+ checkFilmMpaValid(newFilm);
+ checkFilmGenresValid(newFilm);
+
+ int id;
+ if (newFilm.getMpa() == null) {
+ id = insert(ADD_FILM_SIMPLE, newFilm.getName(), newFilm.getDescription(), newFilm.getDuration(),
+ newFilm.getReleaseDate());
+ } else {
+ id = insert(ADD_FILM, newFilm.getName(), newFilm.getDescription(), newFilm.getDuration(),
+ newFilm.getReleaseDate(), newFilm.getMpa().getId());
+ }
+ newFilm.setId(id);
+
+ log.info("Фильму {} присвоен id {}", newFilm.getName(), newFilm.getId());
+ if (newFilm.getGenres() != null && !newFilm.getGenres().isEmpty()) {
+ newFilm.getGenres().forEach(genre -> insert(ADD_GENRE, newFilm.getId(), genre.getId()));
+ }
+
+ enrichFilmByAdditionalInfo(newFilm);
+ return newFilm;
+ }
+
+ /**
+ * Обновляет фильм.
+ * Проверяет поля переданного фильма на соответствие.
+ * Если всё хорошо и переданный фильм существует в контроллере, то создаёт копию и сохраняет в контроллер.
+ *
+ * @param updatedFilm объект фильма, который нужно обновить
+ * @return копия обновлённого фильма
+ */
+ @Override
+ public Film updateFilm(Film updatedFilm) {
+ try {
+ checkFilmMpaValid(updatedFilm);
+ checkFilmGenresValid(updatedFilm);
+
+ if (updatedFilm.getMpa() == null) {
+ update(UPDATE_FILM_SHORT, updatedFilm.getName(), updatedFilm.getDescription(), updatedFilm.getDuration(),
+ updatedFilm.getReleaseDate(), updatedFilm.getId());
+ } else {
+ update(UPDATE_FILM, updatedFilm.getName(), updatedFilm.getDescription(), updatedFilm.getDuration(),
+ updatedFilm.getReleaseDate(), updatedFilm.getMpa().getId(), updatedFilm.getId());
+ }
+
+ if (updatedFilm.getGenres() != null && !updatedFilm.getGenres().isEmpty()) {
+ update(DELETE_GENRES, updatedFilm.getId());
+ updatedFilm.getGenres().forEach(genre ->
+ update(ADD_GENRE, updatedFilm.getId(), genre.getId()));
+ }
+ enrichFilmByAdditionalInfo(updatedFilm);
+ log.info("Фильм {} обновлён в хранилище", updatedFilm.getId());
+ return updatedFilm;
+ } catch (InternalServerException exception) {
+ log.error("Фильм {} не обновлён из-за внутренней ошибки", updatedFilm.getId());
+ throw exception;
+ }
+ }
+
+ /**
+ * Добавляет лайк от пользователя.
+ * Делает запись в БД.
+ */
+ public void addLike(int filmId, int userId) {
+ try {
+ update(ADD_USER_LIKE, filmId, userId);
+ } catch (InternalServerException exception) {
+ log.error("Не удалось добавить лайк для фильма {} от пользователя {}", filmId, userId);
+ throw exception;
+ }
+ }
+
+ /**
+ * Удаляет лайк от пользователя.
+ * Делает запись в БД.
+ */
+ public void removeLike(int filmId, int userId) {
+ try {
+ update(DELETE_USER_LIKE, filmId, userId);
+ } catch (InternalServerException exception) {
+ log.error("Не удалось удалить лайк для фильма {} от пользователя {}", filmId, userId);
+ throw exception;
+ }
+ }
+
+ /**
+ * Возвращает ТОП фильмов по числу лайков
+ */
+ public List getMostPopularFilms(int count) {
+ return findMany(GET_POPULAR_FILMS, count).stream().peek(this::enrichFilmByAdditionalInfo).toList();
+ }
+
+ /**
+ * Обогащает фильм дополнительной информацией.
+ */
+ private Film enrichFilmByAdditionalInfo(Film film) {
+ if (film == null) {
+ String filmNotFound = "Фильм для обогащения не найден";
+ log.error(filmNotFound);
+ throw new NotFoundException(filmNotFound);
+ }
+ film.setGenres(new LinkedHashSet<>(getFilmGenres(film.getId())));
+ film.setMpa(getFilmMpaRating(film.getId()));
+
+ if (film.getLikes() == null) {
+ film.setLikes(new HashSet<>());
+ }
+
+ return film;
+ }
+
+ /**
+ * Формирует список жанров фильма
+ */
+ private List getFilmGenres(int filmId) {
+ List genreIdList = jdbc.queryForList(GET_GENRES_ID, Integer.class, filmId);
+
+ if (genreIdList.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ return genreIdList.stream()
+ .map(genreId -> {
+ Genre genre = new Genre();
+ genre.setId(genreId);
+ return genre;
+ }).peek(genre -> {
+ String genreName = jdbc.queryForObject(GET_GENRE_NAME, String.class, genre.getId());
+ genre.setName(genreName);
+ })
+ .sorted(Comparator.comparing(Genre::getId))
+ .toList();
+ }
+
+ /**
+ * Формирует объект MPA рейтинга
+ */
+ private Mpa getFilmMpaRating(int filmId) {
+ Integer mpaRatingId = jdbc.queryForObject(GET_MPA_ID, Integer.class, filmId);
+ if (mpaRatingId == null) {
+ return null;
+ }
+ String mpaName = jdbc.queryForObject(GET_MPA_NAME, String.class, mpaRatingId);
+ return new Mpa(mpaRatingId, mpaName);
+ }
+
+ /**
+ * Проверяет, что MPA рейтинг фильма существует
+ */
+ private void checkFilmMpaValid(Film film) {
+ Mpa filmMpa = film.getMpa();
+ if (filmMpa == null) {
+ return;
+ }
+ if (!mpaStorage.getMpaList().contains(filmMpa)) {
+ throw new NotFoundException("MPA рейтинг " + filmMpa.getId() + " не найден");
+ }
+ }
+
+ /**
+ * Проверяет, что каждый жанр фильма существует
+ */
+ private void checkFilmGenresValid(Film film) {
+ Set filmGenres = film.getGenres();
+ if (filmGenres == null || filmGenres.isEmpty()) {
+ return;
+ }
+ filmGenres.forEach(genre -> {
+ if (!genreStorage.getGenres().contains(genre)) {
+ throw new NotFoundException("MPA рейтинг " + genre.getId() + " не найден");
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/GenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/GenreDbStorage.java
new file mode 100644
index 0000000..0bd4ab1
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/GenreDbStorage.java
@@ -0,0 +1,41 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.storage.GenreStorage;
+import ru.yandex.practicum.filmorate.storage.dao.mapper.GenreRowMapper;
+
+import java.util.List;
+
+@Repository
+public class GenreDbStorage extends BaseStorage implements GenreStorage {
+ private static final Logger log = LoggerFactory.getLogger(GenreDbStorage.class);
+ private static final String GET_GENRE_BY_ID = "SELECT * FROM genres WHERE id = ?;";
+ private static final String GET_ALL_GENRES = "SELECT * FROM genres ORDER BY id;";
+
+ public GenreDbStorage(JdbcTemplate jdbc, GenreRowMapper mapper) {
+ super(jdbc, mapper);
+ }
+
+ /**
+ * Возвращает жанр по id
+ */
+ public Genre getGenreById(int id) {
+ return findOne(GET_GENRE_BY_ID, id).orElseThrow(() -> {
+ String genreNotFound = "Жанр с id = " + id + " не найден";
+ log.error(genreNotFound);
+ return new NotFoundException(genreNotFound);
+ });
+ }
+
+ /**
+ * Возвращает все жанры в виде списка
+ */
+ public List getGenres() {
+ return findMany(GET_ALL_GENRES);
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/MpaDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/MpaDbStorage.java
new file mode 100644
index 0000000..56abb51
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/MpaDbStorage.java
@@ -0,0 +1,41 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.model.Mpa;
+import ru.yandex.practicum.filmorate.storage.MpaStorage;
+import ru.yandex.practicum.filmorate.storage.dao.mapper.MpaRowMapper;
+
+import java.util.List;
+
+@Repository
+public class MpaDbStorage extends BaseStorage implements MpaStorage {
+ private static final Logger log = LoggerFactory.getLogger(MpaDbStorage.class);
+ private static final String GET_MPA_BY_ID = "SELECT * FROM mpa_ratings WHERE id = ?;";
+ private static final String GET_ALL_MPA = "SELECT * FROM mpa_ratings ORDER BY id;";
+
+ public MpaDbStorage(JdbcTemplate jdbc, MpaRowMapper mapper) {
+ super(jdbc, mapper);
+ }
+
+ /**
+ * Возвращает MPA рейтинг по id
+ */
+ public Mpa getMpaById(int id) {
+ return findOne(GET_MPA_BY_ID, id).orElseThrow(() -> {
+ String mpaNotFound = "Фильм с id = " + id + " не найден";
+ log.error(mpaNotFound);
+ return new NotFoundException(mpaNotFound);
+ });
+ }
+
+ /**
+ * Возвращает все MPA рейтинги в виде списка
+ */
+ public List getMpaList() {
+ return findMany(GET_ALL_MPA);
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/UserDbStorage.java
new file mode 100644
index 0000000..6130631
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/UserDbStorage.java
@@ -0,0 +1,154 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Primary;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+import ru.yandex.practicum.filmorate.exception.InternalServerException;
+import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.storage.UserStorage;
+import ru.yandex.practicum.filmorate.storage.dao.mapper.UserRowMapper;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Primary
+@Repository("userDbStorage")
+public class UserDbStorage extends BaseStorage implements UserStorage {
+ private static final Logger log = LoggerFactory.getLogger(UserDbStorage.class);
+
+ private static final String GET_USER_BY_ID_QUERY = "SELECT * FROM users WHERE id = ?;";
+ private static final String GET_USERS_QUERY = "SELECT * FROM users;";
+ private static final String ADD_USER_QUERY = "INSERT INTO users (name, email, login, birthday)" +
+ "VALUES (?, ?, ?, ?);";
+ private static final String UPDATE_USER_QUERY = "UPDATE users SET name = ?, email = ?, login = ?, birthday = ? " +
+ "WHERE id = ?;";
+ private static final String GET_USER_FRIENDS = "SELECT friend_id FROM users_friendship WHERE user_id = ?;";
+ private static final String ADD_USER_FRIEND = "INSERT INTO users_friendship (user_id, friend_id) VALUES (?, ?);";
+ private static final String DELETE_USER_FRIEND = "DELETE FROM users_friendship WHERE user_id = ? " +
+ "AND friend_id = ?;";
+
+ @Autowired
+ public UserDbStorage(JdbcTemplate jdbc, UserRowMapper mapper) {
+ super(jdbc, mapper);
+ }
+
+ /**
+ * Возвращает пользователя по id из БД
+ */
+ @Override
+ public User getUserById(int id) {
+ User user = findOne(GET_USER_BY_ID_QUERY, id).orElseThrow(() -> {
+ String userNotFound = "Пользователь с id = " + id + " не найден";
+ log.error(userNotFound);
+ return new NotFoundException(userNotFound);
+ });
+ user.setFriends(getUserFriends(id));
+ return user;
+ }
+
+ /**
+ * Возвращает из БД всех пользователей в виде списка
+ */
+ @Override
+ public List getUsers() {
+ try {
+ return findMany(GET_USERS_QUERY);
+ } catch (InternalServerException exception) {
+ log.error("Пользователи не найдены из-за внутренней ошибки");
+ throw exception;
+ }
+ }
+
+ /**
+ * Добавляет нового пользователя.
+ * Присваивает уникальный ID и сохраняет в БД.
+ *
+ * @param newUser объект пользователя, который нужно добавить
+ * @return созданный пользователь с присвоенным ID
+ */
+ @Override
+ public User addUser(User newUser) {
+ int id = insert(ADD_USER_QUERY, newUser.getName(), newUser.getEmail(), newUser.getLogin(),
+ newUser.getBirthday());
+ newUser.setId(id);
+ log.info("Пользователю с логином {} присвоен id {}", newUser.getLogin(), newUser.getId());
+
+ if (newUser.getFriends() == null) {
+ newUser.setFriends(new HashSet<>());
+ }
+
+ log.info("Пользователь {} добавлен в базу", newUser.getId());
+ return newUser;
+ }
+
+ /**
+ * Обновляет пользователя в БД, если он существует.
+ *
+ * @param updatedUser объект пользователя, который нужно обновить
+ * @return обновлённый пользователь
+ */
+ @Override
+ public User updateUser(User updatedUser) {
+ try {
+ update(UPDATE_USER_QUERY, updatedUser.getName(), updatedUser.getEmail(), updatedUser.getLogin(),
+ updatedUser.getBirthday(), updatedUser.getId());
+
+ if (updatedUser.getFriends() == null) {
+ updatedUser.setFriends(new HashSet<>());
+ }
+
+ log.info("Пользователь {} обновлён", updatedUser.getId());
+ return updatedUser;
+ } catch (InternalServerException exception) {
+ log.error("Пользователь {} не обновлён из-за внутренней ошибки", updatedUser.getId());
+ throw exception;
+ }
+ }
+
+ /**
+ * Добавляет в друзья пользователя другому пользователю.
+ * Делает запись в БД.
+ */
+ @Override
+ public void addFriends(int userId, int friendId) {
+ try {
+ jdbc.update(ADD_USER_FRIEND, userId, friendId);
+ } catch (InternalServerException exception) {
+ log.error("Не удалось добавить пользователя {} в друзья {}", friendId, userId);
+ throw exception;
+ }
+ }
+
+ /**
+ * Удаляет одного пользователя из друзей второго пользователя.
+ * Делает запись в БД.
+ */
+ @Override
+ public void removeFriends(int userId, int friendId) {
+ try {
+ jdbc.update(DELETE_USER_FRIEND, userId, friendId);
+ } catch (InternalServerException exception) {
+ log.error("Не удалось удалить пользователя {} из друзей {}", friendId, userId);
+ throw exception;
+ }
+ }
+
+ /**
+ * Возвращает список друзей пользователя в виде списка id
+ */
+ @Override
+ public Set getUserFriends(Integer userId) {
+ try {
+ return new HashSet<>(jdbc.queryForList(GET_USER_FRIENDS, Integer.class, userId));
+ } catch (InternalServerException exception) {
+ String getFriendsError = "Не удалось получить друзей пользователя " + userId;
+ log.error(getFriendsError);
+ throw exception;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/FilmRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/FilmRowMapper.java
new file mode 100644
index 0000000..6529d3e
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/FilmRowMapper.java
@@ -0,0 +1,29 @@
+package ru.yandex.practicum.filmorate.storage.dao.mapper;
+
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.filmorate.model.Film;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.time.LocalDate;
+
+@Component
+public class FilmRowMapper implements RowMapper {
+ @Override
+ public Film mapRow(ResultSet resultSet, int rowNum) throws SQLException {
+ int id = resultSet.getInt("id");
+ String name = resultSet.getString("name");
+ String description = resultSet.getString("description");
+ int duration = resultSet.getInt("duration");
+ LocalDate releaseDate = resultSet.getDate("release_date").toLocalDate();
+
+ return Film.builder()
+ .id(id)
+ .name(name)
+ .description(description)
+ .duration(duration)
+ .releaseDate(releaseDate)
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/GenreRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/GenreRowMapper.java
new file mode 100644
index 0000000..e8257b2
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/GenreRowMapper.java
@@ -0,0 +1,19 @@
+package ru.yandex.practicum.filmorate.storage.dao.mapper;
+
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.filmorate.model.Genre;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+@Component
+public class GenreRowMapper implements RowMapper {
+ @Override
+ public Genre mapRow(ResultSet resultSet, int rowNum) throws SQLException {
+ Genre genre = new Genre();
+ genre.setId(resultSet.getInt("id"));
+ genre.setName(resultSet.getString("name"));
+ return genre;
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/MpaRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/MpaRowMapper.java
new file mode 100644
index 0000000..c84987c
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/MpaRowMapper.java
@@ -0,0 +1,19 @@
+package ru.yandex.practicum.filmorate.storage.dao.mapper;
+
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+@Component
+public class MpaRowMapper implements RowMapper {
+ @Override
+ public Mpa mapRow(ResultSet resultSet, int rowNum) throws SQLException {
+ Mpa mpa = new Mpa();
+ mpa.setId(resultSet.getInt("id"));
+ mpa.setName(resultSet.getString("name"));
+ return mpa;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/UserRowMapper.java b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/UserRowMapper.java
new file mode 100644
index 0000000..99e93ab
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/dao/mapper/UserRowMapper.java
@@ -0,0 +1,33 @@
+package ru.yandex.practicum.filmorate.storage.dao.mapper;
+
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.time.LocalDate;
+import java.util.HashSet;
+import java.util.Set;
+
+@Component
+public class UserRowMapper implements RowMapper {
+ @Override
+ public User mapRow(ResultSet resultSet, int rowNum) throws SQLException {
+ int id = resultSet.getInt("id");
+ String name = resultSet.getString("name");
+ String email = resultSet.getString("email");
+ String login = resultSet.getString("login");
+ LocalDate birthday = resultSet.getDate("birthday").toLocalDate();
+ Set friends = new HashSet<>();
+
+ return User.builder()
+ .id(id)
+ .name(name)
+ .email(email)
+ .login(login)
+ .birthday(birthday)
+ .friends(friends)
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 3eb70b5..bb52638 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,2 +1,7 @@
-logging.level.org.zalando.logbook: TRACE
-
+spring.sql.init.mode=always
+spring.datasource.url=jdbc:h2:file:./db/filmorate
+spring.datasource.driverClassName=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=password
+sql.init.mode=always
+h2.console.enabled=true
\ No newline at end of file
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
new file mode 100644
index 0000000..7bca888
--- /dev/null
+++ b/src/main/resources/data.sql
@@ -0,0 +1,28 @@
+DELETE FROM users_friendship;
+DELETE FROM films_likes;
+DELETE FROM films_genres;
+DELETE FROM films;
+DELETE FROM users;
+DELETE FROM genres;
+DELETE FROM mpa_ratings;
+
+ALTER TABLE mpa_ratings ALTER COLUMN id RESTART WITH 1;
+INSERT INTO mpa_ratings (name) VALUES
+('G'), ('PG'), ('PG-13'), ('R'), ('NC-17');
+
+ALTER TABLE genres ALTER COLUMN id RESTART WITH 1;
+INSERT INTO genres (name) VALUES
+('Комедия'), ('Драма'), ('Мультфильм'), ('Триллер'), ('Документальный'), ('Боевик');
+
+ALTER TABLE users ALTER COLUMN id RESTART WITH 1;
+INSERT INTO users (name, email, login, birthday) VALUES
+('Иван Иванов', 'ivan@mail.com', 'ivan_ivanov', '1990-05-15'),
+('Мария Петрова', 'maria@mail.com', 'maria_pet', '1992-08-22'),
+('Алексей Сидоров', 'alex@mail.com', 'alex_sid', '1988-11-30'),
+('Елена Сидорова', 'elena@mail.com', 'elena_sid', '1988-11-30');
+
+ALTER TABLE films ALTER COLUMN id RESTART WITH 1;
+ALTER TABLE users_friendship ALTER COLUMN id RESTART WITH 1;
+ALTER TABLE films_likes ALTER COLUMN id RESTART WITH 1;
+ALTER TABLE films_genres ALTER COLUMN id RESTART WITH 1;
+
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
new file mode 100644
index 0000000..91cce65
--- /dev/null
+++ b/src/main/resources/schema.sql
@@ -0,0 +1,49 @@
+
+CREATE TABLE IF NOT EXISTS users (
+ id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ name VARCHAR(255),
+ email VARCHAR(255) NOT NULL,
+ login VARCHAR(255) NOT NULL,
+ birthday DATE,
+ CONSTRAINT uq_user_email UNIQUE (email),
+ CONSTRAINT uq_user_login UNIQUE (login)
+);
+
+CREATE TABLE IF NOT EXISTS genres (
+ id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ name VARCHAR(100) NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS mpa_ratings (
+ id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ name VARCHAR(50) NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS films (
+ id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ description VARCHAR(1000),
+ duration INTEGER NOT NULL CHECK (duration > 0),
+ release_date DATE NOT NULL,
+ mpa_rating_id INTEGER REFERENCES mpa_ratings(id) ON DELETE SET NULL,
+ CONSTRAINT release_date_chk CHECK (release_date >= '1895-12-28')
+);
+
+CREATE TABLE IF NOT EXISTS films_genres (
+ id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ film_id INTEGER NOT NULL REFERENCES films(id) ON DELETE CASCADE,
+ genre_id INTEGER NOT NULL REFERENCES genres(id) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS films_likes (
+ id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ film_id INTEGER NOT NULL REFERENCES films(id) ON DELETE CASCADE,
+ user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS users_friendship (
+ id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
+ friend_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
+ CONSTRAINT no_self_friendship_chk CHECK (user_id != friend_id)
+);
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java
index 660412e..a2ce107 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java
@@ -1,13 +1,34 @@
package ru.yandex.practicum.filmorate;
+import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.ComponentScan;
+import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.storage.dao.UserDbStorage;
-@SpringBootTest
+import java.util.Optional;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@ComponentScan(basePackages = "ru.yandex.practicum.filmorate")
class FilmorateApplicationTests {
+ private final UserDbStorage userStorage;
@Test
- void contextLoads() {
- }
+ public void testFindUserById() {
-}
+ Optional userOptional = Optional.of(userStorage.getUserById(1));
+
+ assertThat(userOptional)
+ .isPresent()
+ .hasValueSatisfying(user ->
+ assertThat(user).hasFieldOrPropertyWithValue("id", 1)
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java
index 4a321e2..b0850cd 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java
@@ -1,27 +1,34 @@
package ru.yandex.practicum.filmorate.controller;
+import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.jdbc.core.JdbcTemplate;
+import ru.yandex.practicum.filmorate.dto.film.FilmDto;
+import ru.yandex.practicum.filmorate.dto.film.NewFilmRequest;
+import ru.yandex.practicum.filmorate.dto.film.UpdateFilmRequest;
+import ru.yandex.practicum.filmorate.dto.user.NewUserRequest;
import ru.yandex.practicum.filmorate.exception.NotFoundException;
import ru.yandex.practicum.filmorate.exception.ValidationException;
-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 ru.yandex.practicum.filmorate.storage.FilmStorage;
-import ru.yandex.practicum.filmorate.storage.InMemoryFilmStorage;
-import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage;
-import ru.yandex.practicum.filmorate.storage.UserStorage;
import java.time.LocalDate;
import java.time.Month;
import java.util.List;
-
+import java.util.Objects;
import static org.junit.jupiter.api.Assertions.*;
+
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@ComponentScan(basePackages = "ru.yandex.practicum.filmorate")
class FilmControllerTest {
private static final String FILM_NAME = "Фильм";
private static final String FILM_NAME_2 = "Второй фильм";
@@ -44,38 +51,41 @@ class FilmControllerTest {
private static final String USER_NAME = "Вася";
private static final String USER_EMAIL = "mail@mail.ru";
+ private static final String USER_EMAIL_2 = "mail2@mail.ru";
private static final String USER_LOGIN = "user";
+ private static final String USER_LOGIN_2 = "user2";
private static final LocalDate USER_BIRTHDAY = LocalDate.of(1992, Month.DECEMBER, 12);
private static final Integer USER_ID = 567;
- FilmController filmController;
- UserController userController;
+ private static final String DELETE_FILMS = "DELETE FROM films;";
+ private static final String DELETE_USERS = "DELETE FROM users;";
+
+ private final FilmController filmController;
+ private final UserController userController;
+ private final JdbcTemplate jdbcTemplate;
@BeforeEach
- @DisplayName("Инициализирует контроллер")
- void setUp() {
- UserStorage userStorage = new InMemoryUserStorage();
- UserService userService = new UserService(userStorage);
- userController = new UserController(userService);
-
- FilmStorage filmStorage = new InMemoryFilmStorage();
- FilmService filmService = new FilmService(filmStorage, userStorage);
- filmController = new FilmController(filmService);
+ @DisplayName("Чистим БД")
+ void cleanDatabase() {
+ jdbcTemplate.update(DELETE_FILMS);
+ jdbcTemplate.update(DELETE_USERS);
}
@Test
@DisplayName("При добавлении двух фильмов контроллер должен возвращать их")
void test_getFilms_WhenAddedFilms_ShouldReturnAll() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- Film film2 = Film.builder().name(FILM_NAME_2).description(FILM_DESCRIPTION_2).releaseDate(FILM_RELEASE_DATE_2)
+ NewFilmRequest film2 = NewFilmRequest.builder().name(FILM_NAME_2).description(FILM_DESCRIPTION_2)
+ .releaseDate(FILM_RELEASE_DATE_2)
.duration(FILM_DURATION_2).build();
//when
filmController.addFilm(film);
filmController.addFilm(film2);
- List filmsByController = filmController.getFilms().getBody();
+ List filmsByController = filmController.getFilms().getBody();
//then
assertNotNull(filmsByController, "В контроллере нет фильмов");
@@ -88,13 +98,13 @@ void test_getFilms_WhenAddedFilms_ShouldReturnAll() {
@DisplayName("При добавлении фильма с корректными полями контроллер должен добавить его")
void test_addFilm_WhenCorrectFields_ShouldAddToController() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
.releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
//when
filmController.addFilm(film);
- List filmsByController = filmController.getFilms().getBody();
+ List filmsByController = filmController.getFilms().getBody();
//then
assertNotNull(filmsByController, "В контроллере нет фильмов");
@@ -106,7 +116,7 @@ void test_addFilm_WhenCorrectFields_ShouldAddToController() {
@DisplayName("При добавлении фильма с некорректным описанием контроллер должен выбросить ошибку")
void test_addFilm_WhenIncorrectDescription_ShouldThrowsError() {
//given && when
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION_INCORRECT)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION_INCORRECT)
.releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
@@ -120,7 +130,7 @@ void test_addFilm_WhenIncorrectDescription_ShouldThrowsError() {
@DisplayName("При добавлении фильма с некорректной длительностью контроллер должен выбросить ошибку")
void test_addFilm_WhenIncorrectDuration_ShouldThrowsError() {
//given && when
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
.releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION_INCORRECT).build();
@@ -134,7 +144,7 @@ void test_addFilm_WhenIncorrectDuration_ShouldThrowsError() {
@DisplayName("При добавлении фильма с некорректной датой релиза контроллер должен выбросить ошибку")
void test_addFilm_WhenIncorrectReleaseDate_ShouldThrowsError() {
//given && when
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
.releaseDate(FILM_RELEASE_DATE_INCORRECT)
.duration(FILM_DURATION).build();
@@ -148,14 +158,18 @@ void test_addFilm_WhenIncorrectReleaseDate_ShouldThrowsError() {
@DisplayName("При обновлении фильма с корректными данными контроллер должен обновить его")
void test_updateFilm_WhenCorrectFields_ShouldUpdateInController() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- filmController.addFilm(film);
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
//when
- Film updatedFilm = film.toBuilder().name(FILM_NAME_2).build();
+ UpdateFilmRequest updatedFilm = UpdateFilmRequest.builder().id(filmId).name(FILM_NAME_2)
+ .description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
filmController.updateFilm(updatedFilm);
- List filmsByController = filmController.getFilms().getBody();
+ List filmsByController = filmController.getFilms().getBody();
//then
assertNotNull(filmsByController, "В контроллере нет фильмов");
@@ -167,12 +181,16 @@ void test_updateFilm_WhenCorrectFields_ShouldUpdateInController() {
@DisplayName("При обновлении фильма с некорректным описанием контроллер должен выбросить ошибку")
void test_updateFilm_WhenIncorrectDescription_ShouldThrowsError() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- filmController.addFilm(film);
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
//when
- Film updatedFilm = film.toBuilder().description(FILM_DESCRIPTION_INCORRECT).build();
+ UpdateFilmRequest updatedFilm = UpdateFilmRequest.builder().id(filmId).name(FILM_NAME_2)
+ .description(FILM_DESCRIPTION_INCORRECT)
+ .releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
//then
assertThrows(ValidationException.class,
@@ -184,13 +202,16 @@ void test_updateFilm_WhenIncorrectDescription_ShouldThrowsError() {
@DisplayName("При обновлении фильма с некорректной длительностью контроллер должен выбросить ошибку")
void test_updateFilm_WhenIncorrectDuration_ShouldThrowsError() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- filmController.addFilm(film);
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
//when
- Film updatedFilm = film.toBuilder().duration(FILM_DURATION_INCORRECT).build();
-
+ UpdateFilmRequest updatedFilm = UpdateFilmRequest.builder().id(filmId).name(FILM_NAME_2)
+ .description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION_INCORRECT).build();
//then
assertThrows(ValidationException.class,
() -> filmController.updateFilm(updatedFilm),
@@ -201,12 +222,16 @@ void test_updateFilm_WhenIncorrectDuration_ShouldThrowsError() {
@DisplayName("При добавлении фильма с некорректной датой релиза контроллер должен выбросить ошибку")
void test_updateFilm_WhenIncorrectReleaseDate_ShouldThrowsError() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- filmController.addFilm(film);
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
//when
- Film updatedFilm = film.toBuilder().releaseDate(FILM_RELEASE_DATE_INCORRECT).build();
+ UpdateFilmRequest updatedFilm = UpdateFilmRequest.builder().id(filmId).name(FILM_NAME_2)
+ .description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE_INCORRECT)
+ .duration(FILM_DURATION).build();
//then
assertThrows(ValidationException.class,
@@ -218,12 +243,13 @@ void test_updateFilm_WhenIncorrectReleaseDate_ShouldThrowsError() {
@DisplayName("При получении существующего фильма по id контроллер должен вернуть его")
void test_getFilmById_WhenFilmExists_ShouldReturnOne() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- Film createdFilm = filmController.addFilm(film).getBody();
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
//when
- Film findFilm = filmController.getFilmById(createdFilm.getId()).getBody();
+ FilmDto findFilm = filmController.getFilmById(filmId).getBody();
//then
assertNotNull(findFilm, "В контроллере нет фильмов");
@@ -235,7 +261,7 @@ void test_getFilmById_WhenFilmExists_ShouldReturnOne() {
void test_getFilmById_WhenFilmNotExists_ShouldThrowsError() {
//given && when && then
assertThrows(NotFoundException.class,
- () -> filmController.getFilmById(FILM_ID).getBody(),
+ () -> filmController.getFilmById(FILM_ID),
"Из контроллера получен несуществующий фильм");
}
@@ -243,16 +269,18 @@ void test_getFilmById_WhenFilmNotExists_ShouldThrowsError() {
@DisplayName("При добавлении лайка существующему фильму от существующего пользователя должен вернуться OK 200")
void test_addLikeByUser_WhenFilmAndUserExist_ShouldReturn200() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- Film createdFilm = filmController.addFilm(film).getBody();
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser = userController.addUser(user).getBody();
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY).build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//when
- ResponseEntity response = filmController.addLikeByUser(createdFilm.getId(), createdUser.getId());
+ ResponseEntity response = filmController.addLikeByUser(filmId, userId);
//then
assertEquals(HttpStatus.OK, response.getStatusCode(), "Вернулся не успешный ответ");
@@ -262,12 +290,13 @@ void test_addLikeByUser_WhenFilmAndUserExist_ShouldReturn200() {
@DisplayName("При добавлении лайка существующему фильму от несуществующего пользователя должен вернуть ошибку")
void test_addLikeByUser_WhenUserNotExists_ShouldThrowsError() {
//given && when
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- Film createdFilm = filmController.addFilm(film).getBody();
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
//then
- assertThrows(NotFoundException.class, () -> filmController.addLikeByUser(createdFilm.getId(), USER_ID),
+ assertThrows(NotFoundException.class, () -> filmController.addLikeByUser(filmId, USER_ID),
"Удалось поставить лайк от несуществующего пользователя");
}
@@ -275,11 +304,12 @@ void test_addLikeByUser_WhenUserNotExists_ShouldThrowsError() {
@DisplayName("При добавлении лайка несуществующему фильму от существующего пользователя должен вернуть ошибку")
void test_addLikeByUser_WhenFilmNotExists_ShouldThrowsError() {
//given && when
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser = userController.addUser(user).getBody();
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY).build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//then
- assertThrows(NotFoundException.class, () -> filmController.addLikeByUser(FILM_ID, createdUser.getId()),
+ assertThrows(NotFoundException.class, () -> filmController.addLikeByUser(FILM_ID, userId),
"Удалось поставить лайк несуществующему фильму");
}
@@ -287,16 +317,18 @@ void test_addLikeByUser_WhenFilmNotExists_ShouldThrowsError() {
@DisplayName("При удалении лайка с существующего фильма от существующего пользователя должен вернуть OK 200")
void test_removeLikeByUser_WhenFilmAndUserExist_ShouldReturn200() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- Film createdFilm = filmController.addFilm(film).getBody();
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser = userController.addUser(user).getBody();
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY).build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//when
- filmController.addLikeByUser(createdFilm.getId(), createdUser.getId());
- ResponseEntity response = filmController.removeLikeByUser(createdFilm.getId(), createdUser.getId());
+ filmController.addLikeByUser(filmId, userId);
+ ResponseEntity response = filmController.removeLikeByUser(filmId, userId);
//then
assertEquals(HttpStatus.OK, response.getStatusCode(), "Вернулся не успешный ответ");
@@ -306,12 +338,13 @@ void test_removeLikeByUser_WhenFilmAndUserExist_ShouldReturn200() {
@DisplayName("При удалении лайка с существующего фильма от несуществующего пользователя должен вернуть ошибку")
void test_removeLikeByUser_WhenUserNotExists_ShouldThrowsError() {
//given && when
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- Film createdFilm = filmController.addFilm(film).getBody();
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
//then
- assertThrows(NotFoundException.class, () -> filmController.removeLikeByUser(createdFilm.getId(), USER_ID),
+ assertThrows(NotFoundException.class, () -> filmController.removeLikeByUser(filmId, USER_ID),
"Удалось убрать лайк от несуществующего пользователя");
}
@@ -319,11 +352,12 @@ void test_removeLikeByUser_WhenUserNotExists_ShouldThrowsError() {
@DisplayName("При удалении лайка с несуществующего фильма от существующего пользователя должен вернуть ошибку")
void test_removeLikeByUser_WhenFilmNotExists_ShouldThrowsError() {
//given && when
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser = userController.addUser(user).getBody();
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY).build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//then
- assertThrows(NotFoundException.class, () -> filmController.removeLikeByUser(FILM_ID, createdUser.getId()),
+ assertThrows(NotFoundException.class, () -> filmController.removeLikeByUser(FILM_ID, userId),
"Удалось убрать лайк с несуществующего фильма");
}
@@ -331,23 +365,29 @@ void test_removeLikeByUser_WhenFilmNotExists_ShouldThrowsError() {
@DisplayName("При запросе одного фильма должен вернуть самый популярный")
void test_getMostPopularFilms_WhenRequestOne_ShouldReturnOne() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- Film film2 = Film.builder().name(FILM_NAME_2).description(FILM_DESCRIPTION_2).releaseDate(FILM_RELEASE_DATE_2)
+ NewFilmRequest film2 = NewFilmRequest.builder().name(FILM_NAME_2).description(FILM_DESCRIPTION_2)
+ .releaseDate(FILM_RELEASE_DATE_2)
.duration(FILM_DURATION_2).build();
- Film createdFilm = filmController.addFilm(film).getBody();
- Film createdFilm2 = filmController.addFilm(film2).getBody();
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser = userController.addUser(user).getBody();
- User user2 = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser2 = userController.addUser(user2).getBody();
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
+ int filmId2 = Objects.requireNonNull(filmController.addFilm(film2).getBody()).getId();
+
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY).build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
+
+ NewUserRequest user2 = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL_2).login(USER_LOGIN_2)
+ .birthday(USER_BIRTHDAY).build();
+ int userId2 = Objects.requireNonNull(userController.addUser(user2).getBody()).getId();
//when
- filmController.addLikeByUser(createdFilm.getId(), createdUser.getId());
- filmController.addLikeByUser(createdFilm2.getId(), createdUser.getId());
- filmController.addLikeByUser(createdFilm2.getId(), createdUser2.getId());
- List popularFilms = filmController.getMostPopularFilms(FILM_COUNT_1).getBody();
+ filmController.addLikeByUser(filmId, userId);
+ filmController.addLikeByUser(filmId2, userId2);
+ filmController.addLikeByUser(filmId2, userId2);
+ List popularFilms = filmController.getMostPopularFilms(FILM_COUNT_1).getBody();
//then
assertNotNull(popularFilms, "В контроллере нет популярных фильмов");
@@ -359,23 +399,29 @@ void test_getMostPopularFilms_WhenRequestOne_ShouldReturnOne() {
@DisplayName("Если передано дефолтное количество фильмов, то должен вернуть все (до дефолтного включительно)")
void test_getMostPopularFilms_WhenRequestNothing_ShouldReturnAll() {
//given
- Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ NewFilmRequest film = NewFilmRequest.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
.duration(FILM_DURATION).build();
- Film film2 = Film.builder().name(FILM_NAME_2).description(FILM_DESCRIPTION_2).releaseDate(FILM_RELEASE_DATE_2)
+ NewFilmRequest film2 = NewFilmRequest.builder().name(FILM_NAME_2).description(FILM_DESCRIPTION_2)
+ .releaseDate(FILM_RELEASE_DATE_2)
.duration(FILM_DURATION_2).build();
- Film createdFilm = filmController.addFilm(film).getBody();
- Film createdFilm2 = filmController.addFilm(film2).getBody();
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser = userController.addUser(user).getBody();
- User user2 = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser2 = userController.addUser(user2).getBody();
+ int filmId = Objects.requireNonNull(filmController.addFilm(film).getBody()).getId();
+ int filmId2 = Objects.requireNonNull(filmController.addFilm(film2).getBody()).getId();
+
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY).build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
+
+ NewUserRequest user2 = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL_2).login(USER_LOGIN_2)
+ .birthday(USER_BIRTHDAY).build();
+ int userId2 = Objects.requireNonNull(userController.addUser(user2).getBody()).getId();
//when
- filmController.addLikeByUser(createdFilm.getId(), createdUser.getId());
- filmController.addLikeByUser(createdFilm2.getId(), createdUser.getId());
- filmController.addLikeByUser(createdFilm2.getId(), createdUser2.getId());
- List popularFilms = filmController.getMostPopularFilms(FILM_DEFAULT_COUNT).getBody();
+ filmController.addLikeByUser(filmId, userId);
+ filmController.addLikeByUser(filmId2, userId2);
+ filmController.addLikeByUser(filmId2, userId2);
+ List popularFilms = filmController.getMostPopularFilms(FILM_DEFAULT_COUNT).getBody();
//then
assertNotNull(popularFilms, "В контроллере нет популярных фильмов");
diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/GenreControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/GenreControllerTest.java
new file mode 100644
index 0000000..0dbf263
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/GenreControllerTest.java
@@ -0,0 +1,48 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.ComponentScan;
+import ru.yandex.practicum.filmorate.dto.GenreDto;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@ComponentScan(basePackages = "ru.yandex.practicum.filmorate")
+public class GenreControllerTest {
+ private static final int GENRE_ID = 1;
+ private static final String GENRE_NAME = "Комедия";
+ private static final int GENRES_COUNT = 6;
+ private final GenreController genreController;
+
+ @Test
+ @DisplayName("При запросе по id должен вернуть жанр")
+ void test_getGenreById_ShouldReturnById() {
+ //given && when
+ GenreDto genre = genreController.getGenreById(GENRE_ID).getBody();
+
+ //then
+ assertNotNull(genre, "В контроллере нет жанров");
+ assertEquals(GENRE_NAME, genre.getName(), "В контроллере не верный жанр");
+ }
+
+ @Test
+ @DisplayName("При запросе должен вернуть все жанры")
+ void test_getUsers_ShouldReturnAll() {
+ //given && when
+ List genres = genreController.getGenres().getBody();
+
+ //then
+ assertNotNull(genres, "В контроллере нет жанров");
+ assertEquals(GENRES_COUNT, genres.size(), "В контроллере не верное количество жанров");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/MpaControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/MpaControllerTest.java
new file mode 100644
index 0000000..a4e0385
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/MpaControllerTest.java
@@ -0,0 +1,48 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.ComponentScan;
+import ru.yandex.practicum.filmorate.dto.MpaDto;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@ComponentScan(basePackages = "ru.yandex.practicum.filmorate")
+public class MpaControllerTest {
+ private static final int MPA_ID = 1;
+ private static final String MPA_NAME = "G";
+ private static final int MPA_COUNT = 5;
+ private final MpaController mpaController;
+
+ @Test
+ @DisplayName("При запросе по id должен вернуть рейтинг")
+ void test_getMpaById_ShouldReturnById() {
+ //given && when
+ MpaDto mpa = mpaController.getMpaById(MPA_ID).getBody();
+
+ //then
+ assertNotNull(mpa, "В контроллере нет рейтингом");
+ assertEquals(MPA_NAME, mpa.getName(), "В контроллере не верный рейтинг");
+ }
+
+ @Test
+ @DisplayName("При запросе должен вернуть все рейтинги")
+ void test_getMpaList_ShouldReturnAll() {
+ //given && when
+ List mpaList = mpaController.getMpaList().getBody();
+
+ //then
+ assertNotNull(mpaList, "В контроллере нет рейтингов");
+ assertEquals(MPA_COUNT, mpaList.size(), "В контроллере не верное количество рейтингов");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java
index 3c76ba9..e68b1c5 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java
@@ -1,23 +1,33 @@
package ru.yandex.practicum.filmorate.controller;
+import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.jdbc.core.JdbcTemplate;
+import ru.yandex.practicum.filmorate.dto.user.NewUserRequest;
+import ru.yandex.practicum.filmorate.dto.user.UpdateUserRequest;
+import ru.yandex.practicum.filmorate.dto.user.UserDto;
import ru.yandex.practicum.filmorate.exception.NotFoundException;
import ru.yandex.practicum.filmorate.exception.ValidationException;
-import ru.yandex.practicum.filmorate.model.User;
-import ru.yandex.practicum.filmorate.service.UserService;
-import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage;
-import ru.yandex.practicum.filmorate.storage.UserStorage;
import java.time.LocalDate;
import java.time.Month;
import java.util.List;
+import java.util.Objects;
import static org.junit.jupiter.api.Assertions.*;
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@ComponentScan(basePackages = "ru.yandex.practicum.filmorate")
class UserControllerTest {
private static final String USER_NAME = "Вася";
private static final String USER_NAME_2 = "Петя";
@@ -39,28 +49,32 @@ class UserControllerTest {
private static final Integer USER_ID = 567;
- UserController userController;
+ private static final String DELETE_USERS = "DELETE FROM users;";
+
+ private final UserController userController;
+ private final JdbcTemplate jdbcTemplate;
@BeforeEach
- @DisplayName("Инициализирует контроллер")
- void setUp() {
- UserStorage userStorage = new InMemoryUserStorage();
- UserService userService = new UserService(userStorage);
- userController = new UserController(userService);
+ @DisplayName("Чистим БД")
+ void cleanDatabase() {
+ jdbcTemplate.update(DELETE_USERS);
}
@Test
@DisplayName("При добавлении двух пользователей контроллер должен возвращать их")
void test_getUsers_WhenAddedUsers_ShouldReturnAll() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
- .build();
-
//when
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
userController.addUser(user);
+
+ NewUserRequest user2 = NewUserRequest.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2)
+ .birthday(USER_BIRTHDAY_2)
+ .build();
userController.addUser(user2);
- List usersByController = userController.getUsers().getBody();
+ List usersByController = userController.getUsers().getBody();
//then
assertNotNull(usersByController, "В контроллере нет пользователей");
@@ -75,11 +89,13 @@ void test_getUsers_WhenAddedUsers_ShouldReturnAll() {
@DisplayName("При добавлении пользователя с корректными полями контроллер должен добавить его")
void test_addUser_WhenCorrectFields_ShouldAddToController() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
//when
userController.addUser(user);
- List usersByController = userController.getUsers().getBody();
+ List usersByController = userController.getUsers().getBody();
//then
assertNotNull(usersByController, "В контроллере нет пользователей");
@@ -91,7 +107,7 @@ void test_addUser_WhenCorrectFields_ShouldAddToController() {
@DisplayName("При добавлении пользователя с некорректным логином контроллер должен выбросить ошибку")
void test_addUser_WhenIncorrectLogin_ShouldThrowsError() {
//given && when
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN_INCORRECT)
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN_INCORRECT)
.birthday(USER_BIRTHDAY).build();
//then
@@ -104,11 +120,13 @@ void test_addUser_WhenIncorrectLogin_ShouldThrowsError() {
@DisplayName("При добавлении пользователя без имени в контроллере имя будет равно логину")
void test_addUser_WhenNameIsNull_ShouldReturnNameWithLoginValue() {
//given && when
- User user = User.builder().email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ NewUserRequest user = NewUserRequest.builder().email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
//when
userController.addUser(user);
- List usersByController = userController.getUsers().getBody();
+ List usersByController = userController.getUsers().getBody();
//then
assertNotNull(usersByController, "В контроллере нет пользователей");
@@ -120,7 +138,7 @@ void test_addUser_WhenNameIsNull_ShouldReturnNameWithLoginValue() {
@DisplayName("При добавлении пользователя с датой рождения в будущем контроллер должен выбросить ошибку")
void test_addUser_WhenBirthdayInFuture_ShouldThrowsError() {
//given && when
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
.birthday(USER_BIRTHDAY_INCORRECT).build();
//then
@@ -133,13 +151,18 @@ void test_addUser_WhenBirthdayInFuture_ShouldThrowsError() {
@DisplayName("При обновлении пользователя с корректными полями контроллер должен обновить его")
void test_updateUser_WhenCorrectFields_ShouldUpdateInController() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- userController.addUser(user);
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//when
- User updateUser = user.toBuilder().name(USER_NAME_2).build();
+ UpdateUserRequest updateUser = UpdateUserRequest.builder().id(userId).name(USER_NAME_2).email(USER_EMAIL)
+ .login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
userController.updateUser(updateUser);
- List usersByController = userController.getUsers().getBody();
+ List usersByController = userController.getUsers().getBody();
//then
assertNotNull(usersByController, "В контроллере нет пользователей");
@@ -151,11 +174,16 @@ void test_updateUser_WhenCorrectFields_ShouldUpdateInController() {
@DisplayName("При обновлении пользователя с некорректным логином контроллер должен выбросить ошибку")
void test_updateUser_WhenIncorrectLogin_ShouldThrowsError() {
//given && when
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- userController.addUser(user);
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//when
- User updateUser = user.toBuilder().login(USER_LOGIN_INCORRECT).build();
+ UpdateUserRequest updateUser = UpdateUserRequest.builder().id(userId).name(USER_NAME).email(USER_EMAIL)
+ .login(USER_LOGIN_INCORRECT)
+ .birthday(USER_BIRTHDAY)
+ .build();
//then
assertThrows(ValidationException.class,
@@ -163,33 +191,21 @@ void test_updateUser_WhenIncorrectLogin_ShouldThrowsError() {
"Пользователь обновлён с некорректным логином");
}
- @Test
- @DisplayName("При обновлении пользователя без имени в контроллере имя будет равно логину")
- void test_updateUser_WhenNameIsNull_ShouldReturnNameWithLoginValue() {
- //given && when
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- userController.addUser(user);
-
- //when
- User updateUser = user.toBuilder().name("").build();
- userController.updateUser(updateUser);
- List usersByController = userController.getUsers().getBody();
-
- //then
- assertNotNull(usersByController, "В контроллере нет пользователей");
- assertEquals(1, usersByController.size(), "В контроллере не верное количество пользователей");
- assertEquals(USER_LOGIN, usersByController.get(0).getName(), "Имя пользователя не равно логину");
- }
@Test
@DisplayName("При обновлении пользователя с датой рождения в будущем контроллер должен выбросить ошибку")
void test_updateUser_WhenBirthdayInFuture_ShouldThrowsError() {
//given && when
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- userController.addUser(user);
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//when
- User updateUser = user.toBuilder().birthday(USER_BIRTHDAY_INCORRECT).build();
+ UpdateUserRequest updateUser = UpdateUserRequest.builder().id(userId).name(USER_NAME).email(USER_EMAIL)
+ .login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY_INCORRECT)
+ .build();
//then
assertThrows(ValidationException.class,
@@ -201,11 +217,14 @@ void test_updateUser_WhenBirthdayInFuture_ShouldThrowsError() {
@DisplayName("При получении существующего пользователя по id контроллер должен вернуть его")
void test_getUserById_WhenUserExists_ShouldReturnOne() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser = userController.addUser(user).getBody();
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
+
//when
- User findUser = userController.getUserById(createdUser.getId()).getBody();
+ UserDto findUser = userController.getUserById(userId).getBody();
//then
assertNotNull(findUser, "В контроллере нет пользователей");
@@ -225,14 +244,18 @@ void test_getUserById_WhenUserNotExists_ShouldThrowsError() {
@DisplayName("При добавлении в друзья существующих пользователей ответ должен быть OK 200")
void test_addFriend_WhenUsersExist_ShouldReturn200() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
+
+ NewUserRequest user2 = NewUserRequest.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2)
+ .birthday(USER_BIRTHDAY_2)
.build();
- User createdUser1 = userController.addUser(user).getBody();
- User createdUser2 = userController.addUser(user2).getBody();
+ int userId2 = Objects.requireNonNull(userController.addUser(user2).getBody()).getId();
//when
- ResponseEntity response = userController.addFriend(createdUser1.getId(), createdUser2.getId());
+ ResponseEntity response = userController.addFriend(userId, userId2);
//then
assertEquals(HttpStatus.OK, response.getStatusCode(),
@@ -243,12 +266,14 @@ void test_addFriend_WhenUsersExist_ShouldReturn200() {
@DisplayName("При добавлении в друзья несуществующего пользователя контроллер должен выбросить ошибку")
void test_addFriend_WhenOneUserNotExists_ShouldThrowsError() {
//given && when
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser1 = userController.addUser(user).getBody();
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//then
assertThrows(NotFoundException.class,
- () -> userController.addFriend(createdUser1.getId(), USER_ID),
+ () -> userController.addFriend(userId, USER_ID),
"Удалось добавить в друзья не существующего пользователя");
}
@@ -256,15 +281,19 @@ void test_addFriend_WhenOneUserNotExists_ShouldThrowsError() {
@DisplayName("При удалении из друзей существующих пользователей ответ должен быть OK 200")
void test_removeFriend_WhenFriendsExist_ShouldReturn200() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
.build();
- User createdUser1 = userController.addUser(user).getBody();
- User createdUser2 = userController.addUser(user2).getBody();
- userController.addFriend(createdUser1.getId(), createdUser2.getId());
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
+
+ NewUserRequest user2 = NewUserRequest.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2)
+ .birthday(USER_BIRTHDAY_2)
+ .build();
+ int userId2 = Objects.requireNonNull(userController.addUser(user2).getBody()).getId();
+ userController.addFriend(userId, userId2);
//when
- ResponseEntity response = userController.removeFriend(createdUser1.getId(), createdUser2.getId());
+ ResponseEntity response = userController.removeFriend(userId, userId2);
//then
assertEquals(HttpStatus.OK, response.getStatusCode(),
@@ -275,12 +304,14 @@ void test_removeFriend_WhenFriendsExist_ShouldReturn200() {
@DisplayName("При удалении из друзей несуществующего пользователя контроллер должен выбросить ошибку")
void test_removeFriend_WhenOneFriendNotExist_ShouldReturn200() {
//given && when
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser1 = userController.addUser(user).getBody();
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//then
assertThrows(NotFoundException.class,
- () -> userController.removeFriend(createdUser1.getId(), USER_ID),
+ () -> userController.removeFriend(userId, USER_ID),
"Удалось удалить из друзей несуществующего пользователя");
}
@@ -288,15 +319,19 @@ void test_removeFriend_WhenOneFriendNotExist_ShouldReturn200() {
@DisplayName("При получении всех друзей пользователя должен возвращаться корректный список")
void test_getAllFriends_WhenAddFriends_ShouldReturnOne() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
+
+ NewUserRequest user2 = NewUserRequest.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2)
+ .birthday(USER_BIRTHDAY_2)
.build();
- User createdUser1 = userController.addUser(user).getBody();
- User createdUser2 = userController.addUser(user2).getBody();
+ int userId2 = Objects.requireNonNull(userController.addUser(user2).getBody()).getId();
//when
- userController.addFriend(createdUser1.getId(), createdUser2.getId());
- List userFriends = userController.getAllFriends(createdUser1.getId()).getBody();
+ userController.addFriend(userId, userId2);
+ List userFriends = userController.getAllFriends(userId).getBody();
//then
assertNotNull(userFriends, "У пользователя нет друзей");
@@ -307,11 +342,13 @@ void test_getAllFriends_WhenAddFriends_ShouldReturnOne() {
@DisplayName("При отсутствии друзей у пользователя должен возвращаться пустой список")
void test_getAllFriends_WhenNoFriends_ShouldReturnEmpty() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User createdUser1 = userController.addUser(user).getBody();
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
+ .build();
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
//when
- List userFriends = userController.getAllFriends(createdUser1.getId()).getBody();
+ List userFriends = userController.getAllFriends(userId).getBody();
//then
assertNotNull(userFriends, "Список друзей не проинициализировался");
@@ -322,19 +359,25 @@ void test_getAllFriends_WhenNoFriends_ShouldReturnEmpty() {
@DisplayName("При получении общих друзей пользователей должен возвращаться корректный список")
void test_getCommonFriends_WhenAddSameFriend_ShouldReturnOne() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
.build();
- User user3 = User.builder().name(USER_NAME_3).email(USER_EMAIL_3).login(USER_LOGIN_3).birthday(USER_BIRTHDAY_3)
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
+
+ NewUserRequest user2 = NewUserRequest.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2)
+ .birthday(USER_BIRTHDAY_2)
.build();
- User createdUser1 = userController.addUser(user).getBody();
- User createdUser2 = userController.addUser(user2).getBody();
- User createdUser3 = userController.addUser(user3).getBody();
+ int userId2 = Objects.requireNonNull(userController.addUser(user2).getBody()).getId();
+
+ NewUserRequest user3 = NewUserRequest.builder().name(USER_NAME_3).email(USER_EMAIL_3).login(USER_LOGIN_3)
+ .birthday(USER_BIRTHDAY_3)
+ .build();
+ int userId3 = Objects.requireNonNull(userController.addUser(user3).getBody()).getId();
//when
- userController.addFriend(createdUser1.getId(), createdUser3.getId());
- userController.addFriend(createdUser2.getId(), createdUser3.getId());
- List commonFriends = userController.getCommonFriends(createdUser1.getId(), createdUser2.getId()).getBody();
+ userController.addFriend(userId, userId3);
+ userController.addFriend(userId2, userId3);
+ List commonFriends = userController.getCommonFriends(userId, userId2).getBody();
//then
assertNotNull(commonFriends, "У пользователя нет общих друзей");
@@ -345,19 +388,25 @@ void test_getCommonFriends_WhenAddSameFriend_ShouldReturnOne() {
@DisplayName("При отсутствии общих друзей у пользователей должен возвращаться пустой список")
void test_getCommonFriends_WhenAddNotSameFriend_ShouldReturnEmpty() {
//given
- User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
- User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
+ NewUserRequest user = NewUserRequest.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN)
+ .birthday(USER_BIRTHDAY)
.build();
- User user3 = User.builder().name(USER_NAME_3).email(USER_EMAIL_3).login(USER_LOGIN_3).birthday(USER_BIRTHDAY_3)
+ int userId = Objects.requireNonNull(userController.addUser(user).getBody()).getId();
+
+ NewUserRequest user2 = NewUserRequest.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2)
+ .birthday(USER_BIRTHDAY_2)
+ .build();
+ int userId2 = Objects.requireNonNull(userController.addUser(user2).getBody()).getId();
+
+ NewUserRequest user3 = NewUserRequest.builder().name(USER_NAME_3).email(USER_EMAIL_3).login(USER_LOGIN_3)
+ .birthday(USER_BIRTHDAY_3)
.build();
- User createdUser1 = userController.addUser(user).getBody();
- User createdUser2 = userController.addUser(user2).getBody();
- User createdUser3 = userController.addUser(user3).getBody();
+ int userId3 = Objects.requireNonNull(userController.addUser(user3).getBody()).getId();
//when
- userController.addFriend(createdUser1.getId(), createdUser1.getId());
- userController.addFriend(createdUser2.getId(), createdUser3.getId());
- List commonFriends = userController.getCommonFriends(createdUser1.getId(), createdUser2.getId()).getBody();
+ userController.addFriend(userId, userId2);
+ userController.addFriend(userId2, userId3);
+ List commonFriends = userController.getCommonFriends(userId, userId2).getBody();
//then
assertNotNull(commonFriends, "Список общих друзей не проинициализировался");
diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/dao/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/dao/FilmDbStorageTest.java
new file mode 100644
index 0000000..18c2e09
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/storage/dao/FilmDbStorageTest.java
@@ -0,0 +1,346 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import ru.yandex.practicum.filmorate.exception.InternalServerException;
+import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.storage.FilmStorage;
+import ru.yandex.practicum.filmorate.storage.UserStorage;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@ComponentScan(basePackages = "ru.yandex.practicum.filmorate")
+class FilmDbStorageTest {
+ private static final String FILM_NAME = "Фильм";
+ private static final String FILM_NAME_2 = "Второй фильм";
+
+ private static final String FILM_DESCRIPTION = "Описание фильма";
+ private static final String FILM_DESCRIPTION_2 = "Описание второго фильма";
+ private static final String FILM_DESCRIPTION_INCORRECT = "Очень " + "очень".repeat(199) + "длинное описание";
+
+ private static final LocalDate FILM_RELEASE_DATE = LocalDate.of(1992, Month.DECEMBER, 12);
+ private static final LocalDate FILM_RELEASE_DATE_2 = LocalDate.of(2005, Month.APRIL, 28);
+ private static final LocalDate FILM_RELEASE_DATE_INCORRECT = LocalDate.of(1600, Month.DECEMBER, 5);
+
+ private static final int FILM_DURATION = 100;
+ private static final int FILM_DURATION_2 = 200;
+ private static final int FILM_DURATION_INCORRECT = -100;
+
+ private static final int FILM_ID = 100;
+ private static final int FILM_COUNT_1 = 1;
+
+ private static final String USER_NAME = "Вася";
+ private static final String USER_EMAIL = "mail@mail.ru";
+ private static final String USER_EMAIL_2 = "newMail@mail.ru";
+ private static final String USER_LOGIN = "user";
+ private static final String USER_LOGIN_2 = "newUser";
+ private static final LocalDate USER_BIRTHDAY = LocalDate.of(1992, Month.DECEMBER, 12);
+ private static final Integer USER_ID = 567;
+
+ private static final String DELETE_FILMS = "DELETE FROM films;";
+ private static final String DELETE_USERS = "DELETE FROM users;";
+
+ private final FilmStorage filmStorage;
+ private final UserStorage userStorage;
+ private final JdbcTemplate jdbcTemplate;
+
+ @BeforeEach
+ @DisplayName("Чистим БД")
+ void cleanDatabase() {
+ jdbcTemplate.update(DELETE_FILMS);
+ jdbcTemplate.update(DELETE_USERS);
+ }
+
+ @Test
+ @DisplayName("При получении существующего фильма по id хранилище должно вернуть его")
+ void test_getFilmById_WhenFilmExists_ShouldReturnOne() {
+ //given
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ Film createdFilm = filmStorage.addFilm(film);
+
+ //when
+ Film findFilm = filmStorage.getFilmById(createdFilm.getId());
+
+ //then
+ assertNotNull(findFilm, "В БД нет фильмов");
+ assertEquals(FILM_NAME, findFilm.getName(), "В БД некорректный фильм");
+ }
+
+ @Test
+ @DisplayName("При получении несуществующего фильма по id хранилище должно вернуть ошибку")
+ void test_getFilmById_WhenFilmNotExists_ShouldThrowsError() {
+ //given && when && then
+ assertThrows(NotFoundException.class,
+ () -> filmStorage.getFilmById(FILM_ID),
+ "Из БД получен несуществующий фильм");
+ }
+
+ @Test
+ @DisplayName("При добавлении двух фильмов хранилище должно возвращать их")
+ void test_getFilms_WhenAddedFilms_ShouldReturnAll() {
+ //given
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ Film film2 = Film.builder().name(FILM_NAME_2).description(FILM_DESCRIPTION_2).releaseDate(FILM_RELEASE_DATE_2)
+ .duration(FILM_DURATION_2).build();
+
+ //when
+ filmStorage.addFilm(film);
+ filmStorage.addFilm(film2);
+ List filmsByController = filmStorage.getFilms();
+
+ //then
+ assertNotNull(filmsByController, "В БД нет фильмов");
+ assertEquals(2, filmsByController.size(), "В БД не верное количество фильмов");
+ assertEquals(FILM_NAME, filmsByController.get(0).getName(), "В БД не корректный 1-ый фильм");
+ assertEquals(FILM_NAME_2, filmsByController.get(1).getName(), "В БД не корректный 2-ой фильм");
+ }
+
+ @Test
+ @DisplayName("При добавлении фильма с корректными полями хранилище должно добавить его")
+ void test_addFilm_WhenCorrectFields_ShouldAddToController() {
+ //given
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+
+ //when
+ filmStorage.addFilm(film);
+ List filmsByStorage = filmStorage.getFilms();
+
+ //then
+ assertNotNull(filmsByStorage, "В БД нет фильмов");
+ assertEquals(1, filmsByStorage.size(), "В БД не верное количество фильмов");
+ assertEquals(FILM_NAME, filmsByStorage.get(0).getName(), "В БД некорректный фильм");
+ }
+
+ @Test
+ @DisplayName("При добавлении фильма с некорректным описанием хранилище должно выбросить ошибку")
+ void test_addFilm_WhenIncorrectDescription_ShouldThrowsError() {
+ //given && when
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION_INCORRECT)
+ .releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+
+ //then
+ assertThrows(DataIntegrityViolationException.class,
+ () -> filmStorage.addFilm(film),
+ "Фильм может быть добавлен с некорректным описанием");
+ }
+
+ @Test
+ @DisplayName("При добавлении фильма с некорректной длительностью хранилище должно выбросить ошибку")
+ void test_addFilm_WhenIncorrectDuration_ShouldThrowsError() {
+ //given && when
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION_INCORRECT).build();
+
+ //then
+ assertThrows(DataIntegrityViolationException.class,
+ () -> filmStorage.addFilm(film),
+ "Фильм может быть добавлен с некорректной длительностью");
+ }
+
+ @Test
+ @DisplayName("При добавлении фильма с некорректной датой релиза хранилище должно выбросить ошибку")
+ void test_addFilm_WhenIncorrectReleaseDate_ShouldThrowsError() {
+ //given && when
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION)
+ .releaseDate(FILM_RELEASE_DATE_INCORRECT)
+ .duration(FILM_DURATION).build();
+
+ //then
+ assertThrows(DataIntegrityViolationException.class,
+ () -> filmStorage.addFilm(film),
+ "Фильм может быть добавлен с некорректной датой релиза");
+ }
+
+ @Test
+ @DisplayName("При обновлении фильма с корректными данными хранилище должно обновить его")
+ void test_updateFilm_WhenCorrectFields_ShouldUpdateInController() {
+ //given
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ filmStorage.addFilm(film);
+
+ //when
+ Film updatedFilm = film.toBuilder().name(FILM_NAME_2).build();
+ filmStorage.updateFilm(updatedFilm);
+ List filmsByController = filmStorage.getFilms();
+
+ //then
+ assertNotNull(filmsByController, "В БД нет фильмов");
+ assertEquals(1, filmsByController.size(), "В БД не верное количество фильмов");
+ assertEquals(FILM_NAME_2, filmsByController.get(0).getName(), "В БД некорректный фильм");
+ }
+
+ @Test
+ @DisplayName("При обновлении фильма с некорректным описанием хранилище должно выбросить ошибку")
+ void test_updateFilm_WhenIncorrectDescription_ShouldThrowsError() {
+ //given
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ filmStorage.addFilm(film);
+
+ //when
+ Film updatedFilm = film.toBuilder().description(FILM_DESCRIPTION_INCORRECT).build();
+
+ //then
+ assertThrows(DataIntegrityViolationException.class,
+ () -> filmStorage.updateFilm(updatedFilm),
+ "Фильм может быть обновлён с некорректным описанием");
+ }
+
+ @Test
+ @DisplayName("При обновлении фильма с некорректной длительностью хранилище должно выбросить ошибку")
+ void test_updateFilm_WhenIncorrectDuration_ShouldThrowsError() {
+ //given
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ filmStorage.addFilm(film);
+
+ //when
+ Film updatedFilm = film.toBuilder().duration(FILM_DURATION_INCORRECT).build();
+
+ //then
+ assertThrows(DataIntegrityViolationException.class,
+ () -> filmStorage.updateFilm(updatedFilm),
+ "Фильм может быть обновлён с некорректной длительностью");
+ }
+
+ @Test
+ @DisplayName("При добавлении фильма с некорректной датой релиза хранилище должно выбросить ошибку")
+ void test_updateFilm_WhenIncorrectReleaseDate_ShouldThrowsError() {
+ //given
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ filmStorage.addFilm(film);
+
+ //when
+ Film updatedFilm = film.toBuilder().releaseDate(FILM_RELEASE_DATE_INCORRECT).build();
+
+ //then
+ assertThrows(DataIntegrityViolationException.class,
+ () -> filmStorage.updateFilm(updatedFilm),
+ "Фильм может быть обновлён с некорректной датой релиза");
+ }
+
+ @Test
+ @DisplayName("При добавлении лайка существующему фильму от существующего пользователя должен вернуться OK")
+ void test_addLikeByUser_WhenFilmAndUserExist_ShouldReturn200() {
+ //given && when
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ Film createdFilm = filmStorage.addFilm(film);
+
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User createdUser = userStorage.addUser(user);
+
+ //then
+ assertDoesNotThrow(() -> filmStorage.addLike(createdFilm.getId(), createdUser.getId()),
+ "Не удалось поставить лайк существующему фильму");
+ }
+
+ @Test
+ @DisplayName("При добавлении лайка несуществующему фильму от существующего пользователя должен вернуть ошибку")
+ void test_addLikeByUser_WhenFilmNotExists_ShouldThrowsError() {
+ //given && when
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User createdUser = userStorage.addUser(user);
+
+ //then
+ assertThrows(DataIntegrityViolationException.class, () -> filmStorage.addLike(FILM_ID, createdUser.getId()),
+ "Удалось поставить лайк несуществующему фильму");
+ }
+
+ @Test
+ @DisplayName("При удалении лайка с существующего фильма от существующего пользователя должен вернуть OK")
+ void test_removeLikeByUser_WhenFilmAndUserExist_ShouldReturnOk() {
+ //given
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ Film createdFilm = filmStorage.addFilm(film);
+
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User createdUser = userStorage.addUser(user);
+
+ //when
+ filmStorage.addLike(createdFilm.getId(), createdUser.getId());
+
+ //then
+ assertDoesNotThrow(() -> filmStorage.removeLike(createdFilm.getId(), createdUser.getId()),
+ "Не удалось поставить лайк существующему фильму");
+ }
+
+ @Test
+ @DisplayName("При удалении лайка с существующего фильма от несуществующего пользователя должен вернуть ошибку")
+ void test_removeLikeByUser_WhenUserNotExists_ShouldThrowsError() {
+ //given && when
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ Film createdFilm = filmStorage.addFilm(film);
+
+ //then
+ assertThrows(InternalServerException.class, () -> filmStorage.removeLike(createdFilm.getId(), USER_ID),
+ "Удалось убрать лайк от несуществующего пользователя");
+ }
+
+ @Test
+ @DisplayName("При удалении лайка с несуществующего фильма от существующего пользователя должен вернуть ошибку")
+ void test_removeLikeByUser_WhenFilmNotExists_ShouldThrowsError() {
+ //given && when
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User createdUser = userStorage.addUser(user);
+
+ //then
+ assertThrows(InternalServerException.class, () -> filmStorage.removeLike(FILM_ID, createdUser.getId()),
+ "Удалось убрать лайк с несуществующего фильма");
+ }
+
+ @Test
+ @DisplayName("При запросе одного фильма должен вернуть самый популярный")
+ void test_getMostPopularFilms_WhenRequestOne_ShouldReturnOne() {
+ //given
+ Film film = Film.builder().name(FILM_NAME).description(FILM_DESCRIPTION).releaseDate(FILM_RELEASE_DATE)
+ .duration(FILM_DURATION).build();
+ Film film2 = Film.builder().name(FILM_NAME_2).description(FILM_DESCRIPTION_2).releaseDate(FILM_RELEASE_DATE_2)
+ .duration(FILM_DURATION_2).build();
+ Film createdFilm = filmStorage.addFilm(film);
+ Film createdFilm2 = filmStorage.addFilm(film2);
+
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User createdUser = userStorage.addUser(user);
+ User user2 = User.builder().name(USER_NAME).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY).build();
+ User createdUser2 = userStorage.addUser(user2);
+
+ //when
+ filmStorage.addLike(createdFilm.getId(), createdUser.getId());
+ filmStorage.addLike(createdFilm2.getId(), createdUser.getId());
+ filmStorage.addLike(createdFilm2.getId(), createdUser2.getId());
+ List popularFilms = filmStorage.getMostPopularFilms(FILM_COUNT_1);
+
+ //then
+ assertNotNull(popularFilms, "В БД нет популярных фильмов");
+ assertEquals(1, popularFilms.size(), "В БД не верное количество фильмов");
+ assertEquals(FILM_NAME_2, popularFilms.get(0).getName(), "В БД не корректный фильм");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/dao/GenreDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/dao/GenreDbStorageTest.java
new file mode 100644
index 0000000..012ed08
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/storage/dao/GenreDbStorageTest.java
@@ -0,0 +1,48 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.ComponentScan;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.storage.GenreStorage;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@ComponentScan(basePackages = "ru.yandex.practicum.filmorate")
+class GenreDbStorageTest {
+ private static final int GENRE_ID = 1;
+ private static final String GENRE_NAME = "Комедия";
+ private static final int GENRES_COUNT = 6;
+ private final GenreStorage genreStorage;
+
+ @Test
+ @DisplayName("При запросе по id должен вернуть жанр")
+ void test_getGenreById_ShouldReturnById() {
+ //given && when
+ Genre genre = genreStorage.getGenreById(GENRE_ID);
+
+ //then
+ assertNotNull(genre, "В контроллере нет жанров");
+ assertEquals(GENRE_NAME, genre.getName(), "В контроллере не верный жанр");
+ }
+
+ @Test
+ @DisplayName("При запросе должен вернуть все жанры")
+ void test_getUsers_ShouldReturnAll() {
+ //given && when
+ List genres = genreStorage.getGenres();
+
+ //then
+ assertNotNull(genres, "В контроллере нет жанров");
+ assertEquals(GENRES_COUNT, genres.size(), "В контроллере не верное количество жанров");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/dao/MpaDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/dao/MpaDbStorageTest.java
new file mode 100644
index 0000000..d255b4c
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/storage/dao/MpaDbStorageTest.java
@@ -0,0 +1,48 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.ComponentScan;
+import ru.yandex.practicum.filmorate.model.Mpa;
+import ru.yandex.practicum.filmorate.storage.MpaStorage;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@ComponentScan(basePackages = "ru.yandex.practicum.filmorate")
+class MpaDbStorageTest {
+ private static final int MPA_ID = 1;
+ private static final String MPA_NAME = "G";
+ private static final int MPA_COUNT = 5;
+ private final MpaStorage mpaStorage;
+
+ @Test
+ @DisplayName("При запросе по id должен вернуть жанр")
+ void test_getMpaById_ShouldReturnById() {
+ //given && when
+ Mpa mpa = mpaStorage.getMpaById(MPA_ID);
+
+ //then
+ assertNotNull(mpa, "В контроллере нет рейтингом");
+ assertEquals(MPA_NAME, mpa.getName(), "В контроллере не верный рейтинг");
+ }
+
+ @Test
+ @DisplayName("При запросе должен вернуть все жанры")
+ void test_getMpaList_ShouldReturnAll() {
+ //given && when
+ List mpaList = mpaStorage.getMpaList();
+
+ //then
+ assertNotNull(mpaList, "В контроллере нет рейтингов");
+ assertEquals(MPA_COUNT, mpaList.size(), "В контроллере не верное количество рейтингов");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/dao/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/dao/UserDbStorageTest.java
new file mode 100644
index 0000000..98d5fbe
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/storage/dao/UserDbStorageTest.java
@@ -0,0 +1,186 @@
+package ru.yandex.practicum.filmorate.storage.dao;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.jdbc.core.JdbcTemplate;
+import ru.yandex.practicum.filmorate.exception.NotFoundException;
+import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.storage.UserStorage;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@ComponentScan(basePackages = "ru.yandex.practicum.filmorate")
+class UserDbStorageTest {
+ private static final String USER_NAME = "Вася";
+ private static final String USER_NAME_2 = "Петя";
+
+ private static final String USER_EMAIL = "mail@mail.ru";
+ private static final String USER_EMAIL_2 = "newMail@mail.ru";
+
+ private static final String USER_LOGIN = "user";
+ private static final String USER_LOGIN_2 = "newUser";
+
+ private static final LocalDate USER_BIRTHDAY = LocalDate.of(1992, Month.DECEMBER, 12);
+ private static final LocalDate USER_BIRTHDAY_2 = LocalDate.of(1982, Month.OCTOBER, 22);
+
+ private static final Integer USER_ID = 567;
+ private static final String DELETE_USERS = "DELETE FROM users;";
+
+ private final UserStorage userStorage;
+ private final JdbcTemplate jdbcTemplate;
+
+ @BeforeEach
+ @DisplayName("Чистим БД")
+ void cleanDatabase() {
+ jdbcTemplate.update(DELETE_USERS);
+ }
+
+ @Test
+ @DisplayName("При получении существующего пользователя по id хранилище должно вернуть его")
+ void test_getUserById_WhenUserExists_ShouldReturnOne() {
+ //given
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User createdUser = userStorage.addUser(user);
+
+ //when
+ User findUser = userStorage.getUserById(createdUser.getId());
+
+ //then
+ assertNotNull(findUser, "В БД нет пользователей");
+ assertEquals(USER_NAME, findUser.getName(), "В БД некорректный пользователь");
+ }
+
+ @Test
+ @DisplayName("При получении несуществующего пользователя по id хранилище должно выбросить ошибку")
+ void test_getUserById_WhenUserNotExists_ShouldThrowsError() {
+ //given && when && then
+ assertThrows(NotFoundException.class,
+ () -> userStorage.getUserById(USER_ID),
+ "Из контроллера получен несуществующий пользователь");
+ }
+
+ @Test
+ @DisplayName("При добавлении двух пользователей хранилище должно возвращать их")
+ void test_getUsers_WhenAddedUsers_ShouldReturnAll() {
+ //given
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
+ .build();
+
+ //when
+ userStorage.addUser(user);
+ userStorage.addUser(user2);
+ List usersByController = userStorage.getUsers();
+
+ //then
+ assertNotNull(usersByController, "В БД нет пользователей");
+ assertEquals(2, usersByController.size(), "В БД не верное количество пользователей");
+ assertEquals(USER_NAME, usersByController.get(0).getName(),
+ "В БД не корректный 1-ый пользователь");
+ assertEquals(USER_NAME_2, usersByController.get(1).getName(),
+ "В БД не корректный 2-ой пользователь");
+ }
+
+ @Test
+ @DisplayName("При добавлении пользователя с корректными полями хранилище должно добавить его")
+ void test_addUser_WhenCorrectFields_ShouldAddToStorage() {
+ //given
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+
+ //when
+ userStorage.addUser(user);
+ List usersByController = userStorage.getUsers();
+
+ //then
+ assertNotNull(usersByController, "В БД нет пользователей");
+ assertEquals(1, usersByController.size(), "В БД не верное количество пользователей");
+ assertEquals(USER_NAME, usersByController.get(0).getName(), "В БД некорректный пользователь");
+ }
+
+ @Test
+ @DisplayName("При добавлении в друзья существующих пользователей список друзей должен обновиться")
+ void test_addFriends_WhenUsersExist_ShouldReturnOne() {
+ //given
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
+ .build();
+ User createdUser1 = userStorage.addUser(user);
+ User createdUser2 = userStorage.addUser(user2);
+
+ //when
+ userStorage.addFriends(createdUser1.getId(), createdUser2.getId());
+ List friendsId = new ArrayList<>(userStorage.getUserFriends(createdUser1.getId()));
+
+ //then
+ assertEquals(1, friendsId.size(),
+ "При добавлении в друзья список друзей остался пуст");
+ }
+
+ @Test
+ @DisplayName("При удалении из друзей пользователя список друзей должен обновиться")
+ void test_removeFriends_WhenFriendsExist_ShouldReturnZero() {
+ //given
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
+ .build();
+ User createdUser1 = userStorage.addUser(user);
+ User createdUser2 = userStorage.addUser(user2);
+ userStorage.addFriends(createdUser1.getId(), createdUser2.getId());
+
+ //when
+ userStorage.removeFriends(createdUser1.getId(), createdUser2.getId());
+ List friendsId = new ArrayList<>(userStorage.getUserFriends(createdUser1.getId()));
+
+ //then
+ assertEquals(0, friendsId.size(),
+ "При удалении из друзей пользователь остался в друзьях");
+ }
+
+ @Test
+ @DisplayName("При получении всех друзей пользователя должен возвращаться корректный список")
+ void test_getUserFriends_WhenAddFriends_ShouldReturnOne() {
+ //given
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User user2 = User.builder().name(USER_NAME_2).email(USER_EMAIL_2).login(USER_LOGIN_2).birthday(USER_BIRTHDAY_2)
+ .build();
+ User createdUser1 = userStorage.addUser(user);
+ User createdUser2 = userStorage.addUser(user2);
+
+ //when
+ userStorage.addFriends(createdUser1.getId(), createdUser2.getId());
+ List friendsId = new ArrayList<>(userStorage.getUserFriends(createdUser1.getId()));
+
+ //then
+ assertEquals(1, friendsId.size(),
+ "При добавлении в друзья список друзей остался пуст");
+ }
+
+ @Test
+ @DisplayName("При отсутствии друзей у пользователя должен возвращаться пустой список")
+ void test_getUserFriends_WhenNoFriends_ShouldReturnEmpty() {
+ //given
+ User user = User.builder().name(USER_NAME).email(USER_EMAIL).login(USER_LOGIN).birthday(USER_BIRTHDAY).build();
+ User createdUser1 = userStorage.addUser(user);
+
+ //when
+ List userFriends = new ArrayList<>(userStorage.getUserFriends(createdUser1.getId()));
+
+ //then
+ assertNotNull(userFriends, "Список друзей не проинициализировался");
+ assertEquals(0, userFriends.size(), "Список друзей не пустой");
+ }
+}
\ No newline at end of file