diff --git a/pom.xml b/pom.xml index 870ae8526..0efdef4b2 100644 --- a/pom.xml +++ b/pom.xml @@ -1,241 +1,260 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.7.2 - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.2 + + - ru.practicum - shareit - 0.0.1-SNAPSHOT + ru.practicum + shareit + 0.0.1-SNAPSHOT - ShareIt + ShareIt - - 11 - + + 11 + - - - org.springframework.boot - spring-boot-starter-web - + + + org.springframework.boot + spring-boot-starter-web + - - org.postgresql - postgresql - runtime - - - com.h2database - h2 - runtime - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-validation - - + + org.postgresql + postgresql + runtime + + + org.hibernate.validator + hibernate-validator + 6.0.10.Final + + + org.springframework.boot + spring-boot-starter-validation + + + com.h2database + h2 + runtime + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mockito + mockito-core + test + + + org.springframework.boot + spring-boot-starter + - - - - src/main/resources - true - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - test - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.1.2 - - checkstyle.xml - true - true - true - - - - - check - - compile - - - - - com.puppycrawl.tools - checkstyle - 10.3 - - - - - com.github.spotbugs - spotbugs-maven-plugin - 4.7.0.0 - - Max - High - - - - - check - - - - - - org.jacoco - jacoco-maven-plugin - 0.8.8 - - file - - - - jacoco-initialize - - prepare-agent - - - - jacoco-check - - check - - - - - BUNDLE - - - INSTRUCTION - COVEREDRATIO - 0.01 - - - LINE - COVEREDRATIO - 0.9 - - - BRANCH - COVEREDRATIO - 0.6 - - - COMPLEXITY - COVEREDRATIO - 0.6 - - - METHOD - COVEREDRATIO - 0.7 - - - CLASS - MISSEDCOUNT - 1 - - - - - - - - jacoco-report - test - - report - - - - - - - - - - check - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - com.github.spotbugs - spotbugs-maven-plugin - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - - - - - - coverage - - - - org.jacoco - jacoco-maven-plugin - - - - - + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + src/main/resources + true + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + test + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.2 + + checkstyle.xml + true + true + true + + + + + check + + compile + + + + + com.puppycrawl.tools + checkstyle + 10.3 + + + + + com.github.spotbugs + spotbugs-maven-plugin + 4.7.0.0 + + Max + High + + + + + check + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + file + + + + jacoco-initialize + + prepare-agent + + + + jacoco-check + + check + + + + + BUNDLE + + + INSTRUCTION + COVEREDRATIO + 0.01 + + + LINE + COVEREDRATIO + 0.9 + + + BRANCH + COVEREDRATIO + 0.6 + + + COMPLEXITY + COVEREDRATIO + 0.6 + + + METHOD + COVEREDRATIO + 0.7 + + + CLASS + MISSEDCOUNT + 1 + + + + + + + + jacoco-report + test + + report + + + + + + + + + + check + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + com.github.spotbugs + spotbugs-maven-plugin + + + + + + + com.github.spotbugs + spotbugs-maven-plugin + + + + + + coverage + + + + org.jacoco + jacoco-maven-plugin + + + + + diff --git a/src/main/java/ru/practicum/shareit/Create.java b/src/main/java/ru/practicum/shareit/Create.java new file mode 100644 index 000000000..5b84b9da0 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/Create.java @@ -0,0 +1,4 @@ +package ru.practicum.shareit; + +public interface Create { +} diff --git a/src/main/java/ru/practicum/shareit/ShareItApp.java b/src/main/java/ru/practicum/shareit/ShareItApp.java index a00ad567d..b69dbb5a6 100644 --- a/src/main/java/ru/practicum/shareit/ShareItApp.java +++ b/src/main/java/ru/practicum/shareit/ShareItApp.java @@ -7,6 +7,7 @@ public class ShareItApp { public static void main(String[] args) { + SpringApplication.run(ShareItApp.class, args); } diff --git a/src/main/java/ru/practicum/shareit/Update.java b/src/main/java/ru/practicum/shareit/Update.java new file mode 100644 index 000000000..067ab2926 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/Update.java @@ -0,0 +1,4 @@ +package ru.practicum.shareit; + +public interface Update { +} diff --git a/src/main/java/ru/practicum/shareit/booking/Booking.java b/src/main/java/ru/practicum/shareit/booking/Booking.java deleted file mode 100644 index 2d9c6668d..000000000 --- a/src/main/java/ru/practicum/shareit/booking/Booking.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.booking; - -/** - * TODO Sprint add-bookings. - */ -public class Booking { -} diff --git a/src/main/java/ru/practicum/shareit/booking/BookingController.java b/src/main/java/ru/practicum/shareit/booking/BookingController.java index b94493d49..9bd9026a4 100644 --- a/src/main/java/ru/practicum/shareit/booking/BookingController.java +++ b/src/main/java/ru/practicum/shareit/booking/BookingController.java @@ -1,12 +1,68 @@ package ru.practicum.shareit.booking; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.booking.dto.BookingDTO; +import ru.practicum.shareit.booking.dto.BookingDTOToReturn; +import ru.practicum.shareit.booking.service.BookingService; + +import javax.validation.Valid; +import javax.validation.constraints.PositiveOrZero; +import java.util.List; -/** - * TODO Sprint add-bookings. - */ @RestController @RequestMapping(path = "/bookings") +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@Slf4j +@Validated public class BookingController { + private final BookingService bookingService; + + @PostMapping + public BookingDTOToReturn add(@RequestHeader("X-Sharer-User-Id") Long userId, + @Valid @RequestBody BookingDTO bookingDto) { + log.info("Добавление запроса на аренду пользователем с id {}", userId); + return bookingService.add(userId, bookingDto); + } + + @PatchMapping("/{bookingId}") + public BookingDTOToReturn update(@RequestHeader("X-Sharer-User-Id") Long userId, + @PathVariable Long bookingId, + @RequestParam Boolean approved) { + log.info("Обновление статуса запроса на аренду с id {}", bookingId); + return bookingService.update(userId, bookingId, approved); + + } + + @GetMapping("/{bookingId}") + public BookingDTOToReturn get(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long bookingId) { + log.info("Просмотр запроса на пренду с id {}", bookingId); + return bookingService.get(userId, bookingId); + } + + @GetMapping + public List findByBooker(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(required = false, defaultValue = "ALL") String state, + @PositiveOrZero @RequestParam(name = "from", defaultValue = "0") + Integer from, + @PositiveOrZero @RequestParam(name = "size", defaultValue = "10") + Integer size) { + log.info("Получение списка бронирований пользовалеля с id {}", userId); + return bookingService.getByBooker(userId, state, from, size); + } + + @GetMapping("/owner") + public List findByOwner(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(defaultValue = "ALL") String state, + @PositiveOrZero @RequestParam(name = "from", defaultValue = "0") + Integer from, + @PositiveOrZero @RequestParam(name = "size", defaultValue = "10") + Integer size) { + log.info("Получение списка бронирований для всех вещей пользователя с id {}", userId); + return bookingService.getByOwner(userId, state, from, size); + } + } diff --git a/src/main/java/ru/practicum/shareit/booking/BookingMapper.java b/src/main/java/ru/practicum/shareit/booking/BookingMapper.java new file mode 100644 index 000000000..37f79af8d --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/BookingMapper.java @@ -0,0 +1,69 @@ +package ru.practicum.shareit.booking; + +import lombok.experimental.UtilityClass; +import ru.practicum.shareit.booking.dto.BookingDTO; +import ru.practicum.shareit.booking.dto.BookingDTOForItem; +import ru.practicum.shareit.booking.dto.BookingDTOToReturn; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.Status; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.util.ArrayList; +import java.util.List; + +@UtilityClass +public class BookingMapper { + + public static BookingDTOToReturn toBookingDtoFrom(Booking booking) { + BookingDTOToReturn bookingDto = new BookingDTOToReturn(); + bookingDto.setId(booking.getId()); + bookingDto.setStart(booking.getStart()); + bookingDto.setEnd(booking.getEnd()); + bookingDto.setStatus(booking.getStatus()); + bookingDto.setItem(ItemMapper.toItemToBookingDTO(booking.getItem())); + bookingDto.setBooker(UserMapper.toUserToBookingDTO(booking.getBooker())); + return bookingDto; + } + + public static Booking toBooking(BookingDTO bookingDto, Item item, User user) { + Booking booking = new Booking(); + booking.setStart(bookingDto.getStart()); + booking.setEnd(bookingDto.getEnd()); + booking.setId(bookingDto.getId()); + booking.setStatus(Status.WAITING); + booking.setItem(item); + booking.setBooker(user); + return booking; + } + + public static BookingDTOForItem toBookingDtoForItem(long id, long bookerId) { + BookingDTOForItem bookingDtoForItem = new BookingDTOForItem(); + bookingDtoForItem.setId(id); + bookingDtoForItem.setBookerId(bookerId); + return bookingDtoForItem; + } + + + public static List mapToBookingDtoFrom(Iterable bookings) { + List dtos = new ArrayList<>(); + for (Booking booking : bookings) { + dtos.add(toBookingDtoFrom(booking)); + } + return dtos; + } + + public static BookingDTO toBookingDto(Booking booking) { + BookingDTO bookingDto = new BookingDTO(); + bookingDto.setId(booking.getId()); + bookingDto.setStart(booking.getStart()); + bookingDto.setEnd(booking.getEnd()); + bookingDto.setStatus(booking.getStatus()); + bookingDto.setItemId(booking.getItem() != null ? booking.getItem().getId() : null); + bookingDto.setItemName(booking.getItem() != null ? booking.getItem().getName() : null); + bookingDto.setBookerId(booking.getBooker() != null ? booking.getBooker().getId() : null); + return bookingDto; + } +} diff --git a/src/main/java/ru/practicum/shareit/booking/BookingRepository.java b/src/main/java/ru/practicum/shareit/booking/BookingRepository.java new file mode 100644 index 000000000..7dce6502c --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/BookingRepository.java @@ -0,0 +1,107 @@ +package ru.practicum.shareit.booking; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.Status; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +public interface BookingRepository extends JpaRepository { + + List findByBookerAndStatusOrderByStartDesc(User booker, Status status); + + List findByBookerOrderByStartDesc(User booker); + + Page findByBookerAndStatusOrderByStartDesc(User booker, Status status, Pageable pageable); + + Page findByBookerOrderByStartDesc(User booker, Pageable pageable); + + List findByBookerAndStartAfterOrderByStartDesc(User booker, LocalDateTime now); + + Page findByBookerAndStartAfterOrderByStartDesc(User booker, LocalDateTime now, Pageable pageable); + + List findByBookerAndStartBeforeAndEndAfterOrderByStartDesc(User booker, LocalDateTime s, LocalDateTime e); + + Page findByBookerAndStartBeforeAndEndAfterOrderByStartDesc(User booker, LocalDateTime s, LocalDateTime e, + Pageable pageable); + + List findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc(User booker, LocalDateTime s, LocalDateTime e); + + Page findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc(User booker, LocalDateTime s, + LocalDateTime e, Pageable pageable); + + List findByItemAndBookerAndStartBeforeAndEndBefore(Item item, User booker, LocalDateTime s, + LocalDateTime e); + + @Query("SELECT b FROM Booking b WHERE b.item.id IN" + " (SELECT i.id FROM Item i WHERE i.owner.id = ?1)" + + " ORDER BY b.id DESC") + List findByOwnerAll(long userId); + + @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " + + "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " + + "WHERE i.OWNER_ID = ?1 " + + "ORDER BY b.START_DATE DESC") + List findByOwnerAll(Long i, Pageable pageable); + + @Query("SELECT b FROM Booking b WHERE b.item.id IN " + + "(SELECT i.id FROM Item i WHERE i.owner.id = ?1) AND b.start < ?2 AND b.end > ?2" + + " ORDER BY b.id DESC") + List findByOwnerAndCurrent(long userId, LocalDateTime currentDate); + + @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " + + "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " + + "WHERE i.OWNER_ID = ?1 AND b.START_DATE < ?2 AND b.END_DATE > ?2 " + + "ORDER BY b.START_DATE DESC") + List findByOwnerAndCurrent(Long i, LocalDateTime now, Pageable pageable); + + @Query("SELECT b FROM Booking b WHERE b.item.id IN " + + "(SELECT i.id FROM Item i WHERE i.owner.id = ?1) AND b.end < ?2" + + " ORDER BY b.id DESC") + List findByOwnerAndPast(long userId, LocalDateTime currentDate); + + @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " + + "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " + + "WHERE i.OWNER_ID = ?1 AND b.END_DATE < ?2 AND b.START_DATE < ?2 " + + "ORDER BY b.START_DATE DESC") + List findByOwnerAndPast(Long i, LocalDateTime now, Pageable pageable); + + @Query("SELECT b FROM Booking b WHERE b.item.id IN " + + "(SELECT i.id FROM Item i WHERE i.owner.id = ?1) AND b.start > ?2" + " ORDER BY b.id DESC") + List findByUserAndFuture(long userId, LocalDateTime currentDate); + + @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " + + "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " + + "WHERE i.OWNER_ID = ?1 AND b.START_DATE > ?2 " + + "ORDER BY b.START_DATE DESC") + List findByUserAndFuture(Long i, LocalDateTime s, Pageable pageable); + + @Query("SELECT b FROM Booking b WHERE b.item.id IN " + + "(SELECT i.id FROM Item i WHERE i.owner.id = ?1) AND b.status = ?2" + " ORDER BY b.id DESC") + List findByOwnerAndByStatus(long userId, Status status); + + @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " + + "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " + + "WHERE i.OWNER_ID = ?1 AND b.STATUS LIKE ?2 " + + "ORDER BY b.START_DATE DESC") + List findByOwnerAndByStatus(Long i, String status, Pageable pageable); + + Booking findFirstByStatusAndItemAndStartIsAfter(Status state, Item item, LocalDateTime time, Sort sort); + + Booking findFirstByStatusAndItemAndStartLessThanEqual(Status state, Item item, LocalDateTime time, Sort sort); + + @Query("select b " + + "from Booking b " + + "where b.item in ?1 " + + " and b.status = 'APPROVED'") + List findApprovedForItems(Collection items, Sort sort); + + List findByItemOrderByStartDesc(Item item); +} diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDTO.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTO.java new file mode 100644 index 000000000..2114dd883 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTO.java @@ -0,0 +1,29 @@ +package ru.practicum.shareit.booking.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.booking.model.Status; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +public class BookingDTO { + + private long id; + + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime start; + + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime end; + + private Long itemId; + + private String itemName; + + private Long bookerId; + + private Status status; +} diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOForItem.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOForItem.java new file mode 100644 index 000000000..eb921a5a7 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOForItem.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.booking.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +@JsonInclude(JsonInclude.Include.NON_NULL) +@NoArgsConstructor +public class BookingDTOForItem { + private long id; + private Long bookerId; + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime dateTime; +} diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOToReturn.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOToReturn.java new file mode 100644 index 000000000..e10be31a0 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOToReturn.java @@ -0,0 +1,36 @@ +package ru.practicum.shareit.booking.dto; + +import lombok.Data; +import org.springframework.validation.annotation.Validated; +import ru.practicum.shareit.booking.model.Status; + +import java.time.LocalDateTime; + +@Data +@Validated +public class BookingDTOToReturn { + + private long id; + + private LocalDateTime start; + + private LocalDateTime end; + + private Item item; + + private User booker; + + private Status status; + + @Data + public static class User { + private final long id; + private final String name; + } + + @Data + public static class Item { + private final long id; + private final String name; + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java deleted file mode 100644 index 861de9e01..000000000 --- a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.booking.dto; - -/** - * TODO Sprint add-bookings. - */ -public class BookingDto { -} diff --git a/src/main/java/ru/practicum/shareit/booking/model/Booking.java b/src/main/java/ru/practicum/shareit/booking/model/Booking.java new file mode 100644 index 000000000..dc5399e84 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/model/Booking.java @@ -0,0 +1,44 @@ +package ru.practicum.shareit.booking.model; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.model.User; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Table(name = "bookings", schema = "public") +@Getter +@Setter +@ToString +@RequiredArgsConstructor +public class Booking { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "start_date") + private LocalDateTime start; + + @Column(name = "end_date") + private LocalDateTime end; + + @ManyToOne + @JoinColumn(name = "item_id") + @ToString.Exclude + private Item item; + + @ManyToOne + @JoinColumn(name = "booker_id") + @ToString.Exclude + private User booker; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private Status status; +} diff --git a/src/main/java/ru/practicum/shareit/booking/model/State.java b/src/main/java/ru/practicum/shareit/booking/model/State.java new file mode 100644 index 000000000..2ecd29755 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/model/State.java @@ -0,0 +1,10 @@ +package ru.practicum.shareit.booking.model; + +public enum State { + ALL, + CURRENT, + PAST, + FUTURE, + REJECTED, + WAITING, +} diff --git a/src/main/java/ru/practicum/shareit/booking/model/Status.java b/src/main/java/ru/practicum/shareit/booking/model/Status.java new file mode 100644 index 000000000..3229f84ec --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/model/Status.java @@ -0,0 +1,8 @@ +package ru.practicum.shareit.booking.model; + +public enum Status { + WAITING, + APPROVED, + REJECTED, + CANCELED +} diff --git a/src/main/java/ru/practicum/shareit/booking/service/BookingService.java b/src/main/java/ru/practicum/shareit/booking/service/BookingService.java new file mode 100644 index 000000000..f31050610 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/service/BookingService.java @@ -0,0 +1,18 @@ +package ru.practicum.shareit.booking.service; + +import ru.practicum.shareit.booking.dto.BookingDTO; +import ru.practicum.shareit.booking.dto.BookingDTOToReturn; + +import java.util.List; + +public interface BookingService { + BookingDTOToReturn add(Long userId, BookingDTO bookingDto); + + BookingDTOToReturn update(Long userId, Long bookingId, Boolean approved); + + BookingDTOToReturn get(Long bookingId, Long userId); + + List getByBooker(Long usersId, String status, Integer page, Integer size); + + List getByOwner(Long usersId, String status, Integer page, Integer size); +} diff --git a/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java b/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java new file mode 100644 index 000000000..703fe32f6 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java @@ -0,0 +1,268 @@ +package ru.practicum.shareit.booking.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.booking.BookingMapper; +import ru.practicum.shareit.booking.BookingRepository; +import ru.practicum.shareit.booking.dto.BookingDTO; +import ru.practicum.shareit.booking.dto.BookingDTOToReturn; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.State; +import ru.practicum.shareit.booking.model.Status; +import ru.practicum.shareit.exception.BadRequestException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.exception.StatusBadRequestException; +import ru.practicum.shareit.item.ItemRepository; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.UserRepository; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@Slf4j +public class BookingServiceImpl implements BookingService { + + private final BookingRepository bRepository; + private final ItemRepository iRepository; + private final UserRepository uRepository; + + @Transactional + @Override + public BookingDTOToReturn add(Long userId, BookingDTO bookingDto) { + Item item = iRepository.findById(bookingDto.getItemId()) + .orElseThrow(() -> new NotFoundException("Item not found")); + User user = uRepository.findById(userId) + .orElseThrow(() -> new NotFoundException("User not found")); + if (!item.getAvailable()) { + throw new BadRequestException("You can not book this item"); + } + if (Objects.equals(item.getOwner().getId(), userId)) { + throw new NotFoundException("You cannot book your item"); + } + if (bookingDto.getEnd().isBefore(LocalDateTime.now()) || + bookingDto.getStart().isBefore(LocalDateTime.now()) || + (bookingDto.getEnd().isBefore(bookingDto.getStart()) && + !bookingDto.getEnd().equals(bookingDto.getStart()))) { + throw new BadRequestException("Wrong date"); + } + Booking booking = bRepository.save(BookingMapper.toBooking(bookingDto, item, user)); + return BookingMapper.toBookingDtoFrom(booking); + } + + @Transactional + @Override + public BookingDTOToReturn update(Long userId, Long bookingId, Boolean approved) { + Booking booking; + try { + booking = bRepository.getReferenceById(bookingId); + log.info(booking.toString()); + } catch (NullPointerException e) { + throw new NotFoundException("Booking not found"); + } + Long ownerId = booking.getItem().getOwner().getId(); + + if (!Objects.equals(userId, ownerId)) { + throw new NotFoundException("No rights"); + } + + if (!Objects.equals(String.valueOf(booking.getStatus()), "WAITING")) { + throw new BadRequestException("Status has already been changed"); + } + + if (approved) { + booking.setStatus(Status.APPROVED); + } else { + booking.setStatus(Status.REJECTED); + } + return BookingMapper.toBookingDtoFrom(booking); + } + + @Override + public BookingDTOToReturn get(Long userId, Long bookingId) { + Booking booking = bRepository.findById(bookingId) + .orElseThrow(() -> new NotFoundException(("Booking not found"))); + Long ownerId = booking.getItem().getOwner().getId(); + Long bookerId = booking.getBooker().getId(); + if (Objects.equals(ownerId, userId) || Objects.equals(bookerId, userId)) { + return BookingMapper.toBookingDtoFrom(booking); + } + throw new NotFoundException("No rights"); + } + + @Override + public List getByBooker(Long userId, String status, Integer page, Integer size) { + Optional booker = uRepository.findById(userId); + Pageable pageable; + if (booker.isEmpty()) { + throw new NotFoundException("No rights"); + } + User user = booker.get(); + if (page != null && size != null) { + pageable = PageRequest.of(page / size, size); + return findBookingByBookerByPage(user, status, pageable); + } else { + return findBookingByBooker(user.getId(), status); + } + } + + private List findBookingByBooker(Long userId, String status) { + User booker = uRepository.findById(userId) + .orElseThrow(() -> new NotFoundException("No rights")); + List bookingsByBooker; + State state = stateValidation(status); + switch (state) { + case ALL: + bookingsByBooker = bRepository.findByBookerOrderByStartDesc(booker); + break; + case CURRENT: + bookingsByBooker = bRepository.findByBookerAndStartBeforeAndEndAfterOrderByStartDesc(booker, + LocalDateTime.now(), LocalDateTime.now()); + break; + case PAST: + bookingsByBooker = bRepository.findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc(booker, + LocalDateTime.now(), LocalDateTime.now()); + break; + case FUTURE: + bookingsByBooker = bRepository.findByBookerAndStartAfterOrderByStartDesc(booker, + LocalDateTime.now()); + break; + case WAITING: + bookingsByBooker = bRepository.findByBookerAndStatusOrderByStartDesc(booker, Status.WAITING); + break; + case REJECTED: + bookingsByBooker = bRepository.findByBookerAndStatusOrderByStartDesc(booker, Status.REJECTED); + break; + default: + throw new StatusBadRequestException("Unknown state: UNSUPPORTED_STATUS"); + } + return BookingMapper.mapToBookingDtoFrom(bookingsByBooker); + } + + private List findBookingByBookerByPage(User booker, String status, Pageable pageable) { + Page bookingsPage; + State state = stateValidation(status); + switch (state) { + case ALL: + bookingsPage = bRepository.findByBookerOrderByStartDesc(booker, pageable); + break; + case CURRENT: + bookingsPage = bRepository.findByBookerAndStartBeforeAndEndAfterOrderByStartDesc(booker, + LocalDateTime.now(), LocalDateTime.now(), pageable); + break; + case PAST: + bookingsPage = bRepository.findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc(booker, + LocalDateTime.now(), LocalDateTime.now(), pageable); + break; + case FUTURE: + bookingsPage = bRepository.findByBookerAndStartAfterOrderByStartDesc(booker, LocalDateTime.now(), pageable); + break; + case WAITING: + bookingsPage = bRepository.findByBookerAndStatusOrderByStartDesc(booker, Status.WAITING, pageable); + break; + case REJECTED: + bookingsPage = bRepository.findByBookerAndStatusOrderByStartDesc(booker, Status.REJECTED, pageable); + break; + default: + throw new StatusBadRequestException("Unknown state: UNSUPPORTED_STATUS"); + + } + return BookingMapper.mapToBookingDtoFrom(bookingsPage); + + } + + @Override + public List getByOwner(Long userId, String status, Integer page, Integer size) { + User owner = uRepository.findById(userId).orElseThrow(() -> new NotFoundException("User not found")); + Pageable pageable; + if (page != null && size != null) { + pageable = PageRequest.of(page / size, size); + + return findBookingByOwnerByPage(userId, status, pageable); + } else { + return findBookingByOwner(userId, status); + } + } + + private List findBookingByOwnerByPage(Long userId, String status, Pageable pageable) { + if (uRepository.findById(userId).isEmpty()) { + throw new NotFoundException("User not found"); + } + List bookingsByOwner; + State state = stateValidation(status); + switch (state) { + case ALL: + bookingsByOwner = bRepository.findByOwnerAll(userId, pageable); + break; + case CURRENT: + bookingsByOwner = bRepository.findByOwnerAndCurrent(userId, LocalDateTime.now(), pageable); + break; + case PAST: + bookingsByOwner = bRepository.findByOwnerAndPast(userId, LocalDateTime.now(), pageable); + break; + case FUTURE: + bookingsByOwner = bRepository.findByUserAndFuture(userId, LocalDateTime.now(), pageable); + break; + case WAITING: + bookingsByOwner = bRepository.findByOwnerAndByStatus(userId, String.valueOf(Status.WAITING), pageable); + break; + case REJECTED: + bookingsByOwner = bRepository.findByOwnerAndByStatus(userId, String.valueOf(Status.REJECTED), pageable); + break; + default: + throw new StatusBadRequestException("Unknown state: UNSUPPORTED_STATUS"); + } + return BookingMapper.mapToBookingDtoFrom(bookingsByOwner); + } + + private List findBookingByOwner(Long userId, String status) { + if (uRepository.findById(userId).isEmpty()) { + throw new NotFoundException("User not found"); + } + List bookingsByOwner; + State state = stateValidation(status); + switch (state) { + case ALL: + bookingsByOwner = bRepository.findByOwnerAll(userId); + break; + case CURRENT: + bookingsByOwner = bRepository.findByOwnerAndCurrent(userId, LocalDateTime.now()); + break; + case PAST: + bookingsByOwner = bRepository.findByOwnerAndPast(userId, LocalDateTime.now()); + break; + case FUTURE: + bookingsByOwner = bRepository.findByUserAndFuture(userId, LocalDateTime.now()); + break; + case WAITING: + bookingsByOwner = bRepository.findByOwnerAndByStatus(userId, Status.WAITING); + break; + case REJECTED: + bookingsByOwner = bRepository.findByOwnerAndByStatus(userId, Status.REJECTED); + break; + default: + throw new StatusBadRequestException("Unknown state: UNSUPPORTED_STATUS"); + } + return BookingMapper.mapToBookingDtoFrom(bookingsByOwner); + } + + private State stateValidation(String state) { + try { + Enum.valueOf(State.class, state); + return State.valueOf(state); + } catch (IllegalArgumentException e) { + throw new StatusBadRequestException("Unknown state: UNSUPPORTED_STATUS"); + } + } +} diff --git a/src/main/java/ru/practicum/shareit/exception/BadRequestException.java b/src/main/java/ru/practicum/shareit/exception/BadRequestException.java new file mode 100644 index 000000000..2d29b341e --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/BadRequestException.java @@ -0,0 +1,7 @@ +package ru.practicum.shareit.exception; + +public class BadRequestException extends IllegalArgumentException { + public BadRequestException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java b/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java new file mode 100644 index 000000000..087b580dc --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java @@ -0,0 +1,80 @@ +package ru.practicum.shareit.exception; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageConversionException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.validation.ConstraintViolationException; +import java.util.Map; + +@RestControllerAdvice +@Slf4j +public class ErrorHandler { + + @ExceptionHandler({HttpMessageConversionException.class, BadRequestException.class}) + public ResponseEntity> handleValid(final RuntimeException e) { + log.error("Validation error{}", e.getMessage()); + return new ResponseEntity<>( + Map.of("Ошибка в валидации", e.getMessage()), + HttpStatus.BAD_REQUEST + ); + } + + @ExceptionHandler + public ResponseEntity> handleConstraintViolation(final ConstraintViolationException e) { + log.error("Not valid argument{}", e.getMessage()); + return new ResponseEntity<>( + Map.of("Ошибка в валидации", e.getMessage()), + HttpStatus.BAD_REQUEST + ); + } + + @ExceptionHandler + public ResponseEntity> handleValidation(final MethodArgumentNotValidException e) { + log.error("Not valid argument{}", e.getMessage()); + return new ResponseEntity<>( + Map.of("Ошибка в валидации", e.getMessage()), + HttpStatus.BAD_REQUEST + ); + } + + @ExceptionHandler + public ResponseEntity> handleNotFound(final NotFoundException e) { + log.error("Not found{}", e.getMessage()); + return new ResponseEntity<>( + Map.of("Объект не найден", e.getMessage()), + HttpStatus.NOT_FOUND + ); + } + + @ExceptionHandler + public ResponseEntity> handleStatus(final StatusBadRequestException e) { + log.error("Bad request{}", e.getMessage()); + return new ResponseEntity<>( + Map.of("error", e.getMessage()), + HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler + public ResponseEntity> handleForbiddenError(final ForbiddenException e) { + log.error("No rights{}", e.getMessage()); + return new ResponseEntity<>( + Map.of("Отказано в доступе", e.getMessage()), + HttpStatus.FORBIDDEN + ); + } + + @ExceptionHandler + public ResponseEntity> handleInternalServerError(final Exception e) { + log.error("Server error{}", e.getMessage()); + return new ResponseEntity<>( + Map.of("Серверу не удается обработать запрос", e.getMessage()), + HttpStatus.INTERNAL_SERVER_ERROR + ); + } + +} diff --git a/src/main/java/ru/practicum/shareit/exception/ForbiddenException.java b/src/main/java/ru/practicum/shareit/exception/ForbiddenException.java new file mode 100644 index 000000000..926615376 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/ForbiddenException.java @@ -0,0 +1,7 @@ +package ru.practicum.shareit.exception; + +public class ForbiddenException extends RuntimeException { + public ForbiddenException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/practicum/shareit/exception/NotFoundException.java b/src/main/java/ru/practicum/shareit/exception/NotFoundException.java new file mode 100644 index 000000000..74bf630cf --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/NotFoundException.java @@ -0,0 +1,11 @@ +package ru.practicum.shareit.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.NOT_FOUND) +public class NotFoundException extends RuntimeException { + public NotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/practicum/shareit/exception/StatusBadRequestException.java b/src/main/java/ru/practicum/shareit/exception/StatusBadRequestException.java new file mode 100644 index 000000000..d8817ac67 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/exception/StatusBadRequestException.java @@ -0,0 +1,11 @@ +package ru.practicum.shareit.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.NOT_FOUND) +public class StatusBadRequestException extends RuntimeException { + public StatusBadRequestException(String s) { + super(s); + } +} diff --git a/src/main/java/ru/practicum/shareit/item/CommentRepository.java b/src/main/java/ru/practicum/shareit/item/CommentRepository.java new file mode 100644 index 000000000..230fb5b27 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/CommentRepository.java @@ -0,0 +1,14 @@ +package ru.practicum.shareit.item; + +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; + +import java.util.List; + +public interface CommentRepository extends JpaRepository { + List findAllByItem(Item item); + + List findAllByItemIdIn(List id, Sort created); +} diff --git a/src/main/java/ru/practicum/shareit/item/ItemController.java b/src/main/java/ru/practicum/shareit/item/ItemController.java index bb17668ba..07406e653 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemController.java +++ b/src/main/java/ru/practicum/shareit/item/ItemController.java @@ -1,12 +1,71 @@ package ru.practicum.shareit.item; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.item.dto.CommentDTO; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.item.dto.ItemDTOWithBookings; +import ru.practicum.shareit.item.service.ItemService; + +import javax.validation.Valid; +import javax.validation.constraints.Positive; +import javax.validation.constraints.PositiveOrZero; +import java.util.List; -/** - * TODO Sprint add-controllers. - */ @RestController @RequestMapping("/items") +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@Slf4j public class ItemController { + + private final ItemService itemService; + + @PostMapping + public ItemDTO add(@RequestHeader("X-Sharer-User-Id") Long userId, @Valid @RequestBody ItemDTO itemDto) { + log.info("Добавления новой вещи пользователем с id {}", userId); + return itemService.add(userId, itemDto); + } + + @PatchMapping("/{itemId}") + public ItemDTO update(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long itemId, + @RequestBody ItemDTO itemDto) { + log.info("Обновление данные о вещи"); + return itemService.update(userId, itemId, itemDto); + } + + @GetMapping("/{itemId}") + public ItemDTOWithBookings get(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long itemId) { + log.info("Получение вещи с id {}", itemId); + return itemService.get(userId, itemId); + } + + @GetMapping + public List getAllByOwner(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(name = "from", defaultValue = "0") + @PositiveOrZero Integer from, + @RequestParam(name = "size", defaultValue = "10") + @Positive Integer size) { + log.info("Получение всех вещей пользователя с id {}", userId); + return itemService.getAllByOwner(userId, from, size); + } + + @GetMapping("/search") + public List getAllByText(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam String text, + @RequestParam(name = "from", defaultValue = "0") + @PositiveOrZero Integer from, + @RequestParam(name = "size", defaultValue = "10") + @Positive Integer size) { + log.info("Получение вещей для аренды содержащие в названии или описании текст {}", text); + return itemService.getForRent(text, from, size); + } + + @PostMapping("{itemId}/comment") + public CommentDTO addComment(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long itemId, + @Valid @RequestBody CommentDTO itemDtoWithComment) { + log.info("Добавление комментария для вещи с id {}", itemId); + return itemService.addComment(userId, itemId, itemDtoWithComment); + } } diff --git a/src/main/java/ru/practicum/shareit/item/ItemRepository.java b/src/main/java/ru/practicum/shareit/item/ItemRepository.java new file mode 100644 index 000000000..1b13aa370 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/ItemRepository.java @@ -0,0 +1,35 @@ +package ru.practicum.shareit.item; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import java.util.List; + +public interface ItemRepository extends JpaRepository { + @Query(nativeQuery = true, value = "SELECT * FROM items AS i " + + "WHERE ((LOWER(name) iLike CONCAT('%', LOWER(?1), '%')) " + + "OR (LOWER(description) Like CONCAT('%', LOWER(?1), '%'))) " + + "AND (available)") + List findItemsByNameOrDescription(String substring); + + @Query(nativeQuery = true, value = "SELECT * FROM items " + + "WHERE ((LOWER(name) Like CONCAT('%', LOWER(?1), '%')) " + + "OR (LOWER(description) Like CONCAT('%', LOWER(?1), '%'))) " + + "AND (available)") + Page findItemsByNameOrDescription(String substring, Pageable pageable); + + @Query(nativeQuery = true, value = "SELECT * FROM items AS i WHERE i.REQUEST_ID = ?1") + List findByRequest(Long idRequest); + + List findByOwner(User user); + + Page findByOwner(User user, Pageable pageable); + + List findAllByRequestIdInAndAvailableTrue(List items); + +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/item/dto/CommentDTO.java b/src/main/java/ru/practicum/shareit/item/dto/CommentDTO.java new file mode 100644 index 000000000..e3c944209 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/CommentDTO.java @@ -0,0 +1,21 @@ +package ru.practicum.shareit.item.dto; + +import lombok.Data; + +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +@Data +public class CommentDTO { + + private Long id; + + @Size(min = 1, max = 1000) + private String text; + + private String itemName; + + private String authorName; + + private LocalDateTime created; +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDTO.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDTO.java new file mode 100644 index 000000000..c448ee7d0 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemDTO.java @@ -0,0 +1,32 @@ +package ru.practicum.shareit.item.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +public class ItemDTO { + + private long id; + + @NotBlank + private String name; + + @NotBlank + private String description; + + @NotNull + private Boolean available; + + private User owner; + + private Long requestId; + + @Data + public static class User { + private final long id; + private final String name; + private final String email; + } +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithBookings.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithBookings.java new file mode 100644 index 000000000..c2318cf18 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithBookings.java @@ -0,0 +1,36 @@ +package ru.practicum.shareit.item.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.booking.dto.BookingDTOForItem; + +import java.util.List; + +@Data +@NoArgsConstructor +public class ItemDTOWithBookings { + private long id; + + private String name; + + private String description; + + private Boolean available; + + private User owner; + + private Long request; + + private BookingDTOForItem nextBooking; + + private BookingDTOForItem lastBooking; + + private List comments; + + @Data + public static class User { + private final long id; + private final String name; + private final String email; + } +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithComment.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithComment.java new file mode 100644 index 000000000..7f248c086 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithComment.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.item.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ItemDTOWithComment { + + private Long id; + + private String text; + + private String itemName; + + private String authorName; + + private LocalDateTime created; +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithDate.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithDate.java new file mode 100644 index 000000000..76bf6ba58 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithDate.java @@ -0,0 +1,34 @@ +package ru.practicum.shareit.item.dto; + +import lombok.*; +import ru.practicum.shareit.booking.dto.BookingDTOForItem; + +import java.util.List; + +@Data +@NoArgsConstructor +public class ItemDTOWithDate { + private long id; + + private String name; + + private String description; + + private Boolean available; + + private User owner; + + private Long request; + + private BookingDTOForItem nextBooking; + + private BookingDTOForItem lastBooking; + + private List comments; + + @Data + public static class User { + private final long id; + private final String name; + } +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java deleted file mode 100644 index 9319d7d73..000000000 --- a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.item.dto; - -/** - * TODO Sprint add-controllers. - */ -public class ItemDto { -} diff --git a/src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java b/src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java new file mode 100644 index 000000000..0f12686f1 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java @@ -0,0 +1,42 @@ +package ru.practicum.shareit.item.mapper; + +import lombok.experimental.UtilityClass; +import ru.practicum.shareit.item.dto.CommentDTO; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.model.User; + +import java.util.ArrayList; +import java.util.List; + +@UtilityClass +public class CommentMapper { + + public static CommentDTO toCommentDto(Comment comment) { + CommentDTO itemDtoWithComment = new CommentDTO(); + itemDtoWithComment.setId(comment.getId()); + itemDtoWithComment.setText(comment.getText()); + itemDtoWithComment.setItemName(comment.getItem().getName()); + itemDtoWithComment.setAuthorName(comment.getAuthor().getName()); + itemDtoWithComment.setCreated(comment.getCreated()); + return itemDtoWithComment; + } + + public static Comment toComment(CommentDTO itemDtoWithComment, Item item, User author) { + Comment comment = new Comment(); + comment.setId(comment.getId()); + comment.setText(itemDtoWithComment.getText()); + comment.setItem(item); + comment.setAuthor(author); + return comment; + } + + + public static List mapToCommentDto(Iterable comments) { + List dtos = new ArrayList<>(); + for (Comment comment : comments) { + dtos.add(toCommentDto(comment)); + } + return dtos; + } +} diff --git a/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java new file mode 100644 index 000000000..5be93b160 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java @@ -0,0 +1,96 @@ +package ru.practicum.shareit.item.mapper; + +import lombok.experimental.UtilityClass; +import ru.practicum.shareit.booking.BookingMapper; +import ru.practicum.shareit.booking.dto.BookingDTOToReturn; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.item.dto.ItemDTOWithBookings; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.RequestRepository; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@UtilityClass +public class ItemMapper { + + public static ItemDTO toItemDto(Item item) { + ItemDTO itemDto = new ItemDTO(); + itemDto.setId(item.getId()); + itemDto.setName(item.getName()); + itemDto.setDescription(item.getDescription()); + itemDto.setAvailable(item.getAvailable()); + if (item.getRequestId() != null) { + itemDto.setRequestId(item.getRequestId().getId()); + } + return itemDto; + } + + public static ItemDTOWithBookings toItemDtoWithBookings(Item item) { + ItemDTOWithBookings itemDto = new ItemDTOWithBookings(); + itemDto.setId(item.getId()); + itemDto.setName(item.getName()); + itemDto.setDescription(item.getDescription()); + itemDto.setAvailable(item.getAvailable()); + itemDto.setOwner(UserMapper.toUserToItemWithBookingsDto(item.getOwner())); + return itemDto; + + } + + public static Item toItem(ItemDTO itemDto, User user, RequestRepository requestRepository) { + Item item = new Item(); + item.setId(itemDto.getId()); + item.setName(itemDto.getName()); + item.setDescription(itemDto.getDescription()); + item.setAvailable(itemDto.getAvailable()); + item.setOwner(user); + if (itemDto.getRequestId() != null) { + item.setRequestId(requestRepository.getReferenceById(itemDto.getRequestId())); + } + return item; + } + + public static List mapToItemDto(Iterable items) { + List dtos = new ArrayList<>(); + for (Item item : items) { + dtos.add(toItemDto(item)); + } + return dtos; + } + + public static BookingDTOToReturn.Item toItemToBookingDTO(Item item) { + return new BookingDTOToReturn.Item(item.getId(), item.getName()); + } + + + public static ItemDTOWithBookings toDtoWithBookings(Item item, List bookings, + List comments) { + ItemDTOWithBookings iDTO = new ItemDTOWithBookings(); + iDTO.setId(item.getId()); + iDTO.setName(item.getName()); + iDTO.setDescription(item.getDescription()); + iDTO.setAvailable(item.getAvailable()); + bookings.stream() + .filter(b -> !b.getStart().isAfter(LocalDateTime.now())) + .findFirst() + .ifPresent(lastBooking -> iDTO.setLastBooking(BookingMapper + .toBookingDtoForItem(lastBooking.getId(), lastBooking.getBooker().getId()))); + + bookings.stream() + .filter(b -> b.getStart().isAfter(LocalDateTime.now())) + .reduce((first, second) -> second) + .ifPresent(nextBooking -> iDTO.setNextBooking(BookingMapper + .toBookingDtoForItem(nextBooking.getId(), nextBooking.getBooker().getId()))); + + iDTO.setComments(CommentMapper.mapToCommentDto(comments)); + return iDTO; + } + +} + + diff --git a/src/main/java/ru/practicum/shareit/item/model/Comment.java b/src/main/java/ru/practicum/shareit/item/model/Comment.java new file mode 100644 index 000000000..09b17be6b --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/model/Comment.java @@ -0,0 +1,41 @@ +package ru.practicum.shareit.item.model; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import ru.practicum.shareit.user.model.User; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +@Entity +@Table(name = "comments", schema = "public") +@Getter +@Setter +@RequiredArgsConstructor +public class Comment { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @Size(min = 1, max = 200) + @Column(nullable = false) + private String text; + + @ManyToOne + @JoinColumn(name = "item_id") + @ToString.Exclude + private Item item; + + @ManyToOne + @JoinColumn(name = "author_id") + @ToString.Exclude + private User author; + + @Column(nullable = false) + private LocalDateTime created = LocalDateTime.now(); +} diff --git a/src/main/java/ru/practicum/shareit/item/model/Item.java b/src/main/java/ru/practicum/shareit/item/model/Item.java index 44eb73ddc..a584fe4cd 100644 --- a/src/main/java/ru/practicum/shareit/item/model/Item.java +++ b/src/main/java/ru/practicum/shareit/item/model/Item.java @@ -1,7 +1,58 @@ package ru.practicum.shareit.item.model; -/** - * TODO Sprint add-controllers. - */ +import lombok.*; +import org.hibernate.Hibernate; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Objects; + +@Entity +@Table(name = "items", schema = "public") +@Getter +@Setter +@ToString +@RequiredArgsConstructor public class Item { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @NotBlank + @Column(nullable = false) + private String name; + + @NotBlank + @Column(nullable = false) + private String description; + + @NotNull + @Column + private Boolean available; + + @ManyToOne + @JoinColumn(name = "owner_id") + @ToString.Exclude + private User owner; + + @ManyToOne + @JoinColumn(name = "request_id") + private ItemRequest requestId; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; + Item item = (Item) o; + return id != 0 && Objects.equals(id, item.id); + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } } diff --git a/src/main/java/ru/practicum/shareit/item/service/ItemService.java b/src/main/java/ru/practicum/shareit/item/service/ItemService.java new file mode 100644 index 000000000..cb5429829 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/service/ItemService.java @@ -0,0 +1,24 @@ +package ru.practicum.shareit.item.service; + +import ru.practicum.shareit.item.dto.CommentDTO; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.item.dto.ItemDTOWithBookings; + +import java.util.List; + +public interface ItemService { + + ItemDTO add(Long userId, ItemDTO itemDto); + + ItemDTOWithBookings get(Long userId, Long itemId); + + ItemDTO update(Long userId, Long itemId, ItemDTO itemDto); + + List getAllByOwner(Long userId, Integer page, Integer size); + + List getAllByText(String substring); + + CommentDTO addComment(Long authorId, Long itemId, CommentDTO comment); + + List getForRent(String substring, Integer page, Integer size); +} diff --git a/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java b/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java new file mode 100644 index 000000000..816134bbb --- /dev/null +++ b/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java @@ -0,0 +1,183 @@ +package ru.practicum.shareit.item.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.booking.BookingMapper; +import ru.practicum.shareit.booking.BookingRepository; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.Status; +import ru.practicum.shareit.exception.BadRequestException; +import ru.practicum.shareit.exception.ForbiddenException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.item.CommentRepository; +import ru.practicum.shareit.item.ItemRepository; +import ru.practicum.shareit.item.dto.CommentDTO; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.item.dto.ItemDTOWithBookings; +import ru.practicum.shareit.item.mapper.CommentMapper; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.RequestRepository; +import ru.practicum.shareit.user.UserRepository; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toList; +import static org.springframework.data.domain.Sort.Direction.ASC; +import static org.springframework.data.domain.Sort.Direction.DESC; + +@Service +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@Transactional(readOnly = true) +@Slf4j +public class ItemServiceImpl implements ItemService { + + private final ItemRepository itemRepository; + private final UserRepository userRepository; + private final BookingRepository bookingRepository; + private final CommentRepository commentRepository; + + private final RequestRepository requestRepository; + + @Transactional + @Override + public ItemDTO add(Long userId, ItemDTO itemDto) throws BadRequestException { + User user = userRepository.findById(userId).orElseThrow(() -> new NotFoundException("User not found")); + Item item = itemRepository.save(ItemMapper.toItem(itemDto, user, requestRepository)); + log.info(item.toString()); + return ItemMapper.toItemDto(item); + } + + @Transactional + @Override + public ItemDTO update(Long userId, Long itemId, ItemDTO itemDto) throws BadRequestException { + Item item = itemRepository.findById(itemId).orElseThrow(() -> new NotFoundException("Item not found")); + User user = item.getOwner(); + if (Objects.equals(user.getId(), userId)) { + if (itemDto.getName() != null && !itemDto.getName().isBlank()) { + item.setName(itemDto.getName()); + } + if (itemDto.getDescription() != null && !itemDto.getDescription().isBlank()) { + item.setDescription(itemDto.getDescription()); + } + if (itemDto.getAvailable() != null) { + item.setAvailable(itemDto.getAvailable()); + } + return ItemMapper.toItemDto(item); + } + throw new ForbiddenException("No rights"); + } + + @Override + public ItemDTOWithBookings get(Long userId, Long itemId) { + Item item = itemRepository.findById(itemId).orElseThrow(() -> new NotFoundException("Item not found")); + ItemDTOWithBookings itemDto = ItemMapper.toItemDtoWithBookings(item); + List comments = commentRepository.findAllByItem(item); + itemDto.setComments(CommentMapper.mapToCommentDto(comments)); + if (Objects.equals(item.getOwner().getId(), userId)) { + Booking nextBooking = bookingRepository.findFirstByStatusAndItemAndStartIsAfter(Status.APPROVED, item, + LocalDateTime.now(), Sort.by(ASC, "start")); + Booking lastBooking = bookingRepository.findFirstByStatusAndItemAndStartLessThanEqual(Status.APPROVED, item, + LocalDateTime.now(), Sort.by(DESC, "end")); + if (nextBooking != null) { + itemDto.setNextBooking(BookingMapper.toBookingDtoForItem(nextBooking.getId(), + nextBooking.getBooker().getId())); + } + if (lastBooking != null) itemDto.setLastBooking(BookingMapper.toBookingDtoForItem(lastBooking.getId(), + lastBooking.getBooker().getId())); + } + return itemDto; + } + + @Override + public List getAllByOwner(Long userId, Integer page, Integer size) { + User user = userRepository.findById(userId).orElseThrow(() -> new NotFoundException("User not found")); + List items = new ArrayList<>(); + if (page != null && size != null) { + Pageable pageable = PageRequest.of(page / size, size); + Page itemsPage = itemRepository.findByOwner(user, pageable); + for (Item item : itemsPage) { + items.add(item); + } + } else { + items = itemRepository.findByOwner(user); + } + + log.info(userId.toString()); + + log.info(String.valueOf(items.size())); + Map> approvedBookings = + bookingRepository.findApprovedForItems(items, Sort.by(DESC, "start")) + .stream() + .collect(groupingBy(Booking::getItem, toList())); + log.info(approvedBookings.toString()); + List results = new ArrayList<>(); + Map> comments = + commentRepository.findAllByItemIdIn( + items.stream() + .map(Item::getId) + .collect(Collectors.toUnmodifiableList()), + Sort.by(Sort.Direction.ASC, "created")).stream() + .collect(groupingBy(c -> c.getItem().getId(), Collectors.toUnmodifiableList())); + log.info(comments.toString()); + for (Item item : items) { + ItemDTOWithBookings itemInfo = ItemMapper.toDtoWithBookings( + item, + approvedBookings.getOrDefault(item, Collections.emptyList()), + comments.getOrDefault(item, Collections.emptyList()) + ); + log.info(itemInfo.toString()); + results.add(itemInfo); + } + return results; + } + + @Override + public List getAllByText(String substring) { + if (substring.isBlank()) { + return Collections.emptyList(); + } + return ItemMapper.mapToItemDto(itemRepository.findItemsByNameOrDescription(substring)); + } + + @Transactional + @Override + public CommentDTO addComment(Long authorId, Long itemId, CommentDTO comment) { + Item item = itemRepository.findById(itemId).orElseThrow(() -> new NotFoundException("Item not found")); + User author = userRepository.findById(authorId).orElseThrow(() -> new NotFoundException("User not found")); + List bookings = bookingRepository + .findByItemAndBookerAndStartBeforeAndEndBefore(item, author, LocalDateTime.now(), LocalDateTime.now()); + if (bookings.isEmpty()) { + throw new BadRequestException("Booking is empty"); + } + if (comment == null) { + throw new BadRequestException("Comment is empty"); + } + Comment comment1 = CommentMapper.toComment(comment, item, author); + return CommentMapper.toCommentDto(commentRepository.save(comment1)); + } + + @Override + public List getForRent(String substring, Integer page, Integer size) { + if (!Objects.equals(substring, "")) { + if (page != null && size != null) { + Pageable pageable = PageRequest.of(page / size, size); + return ItemMapper.mapToItemDto(itemRepository.findItemsByNameOrDescription(substring, pageable)); + } + return ItemMapper.mapToItemDto(itemRepository.findItemsByNameOrDescription(substring)); + } + return new ArrayList<>(); + } +} diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/ItemRequest.java deleted file mode 100644 index 95d6f23c8..000000000 --- a/src/main/java/ru/practicum/shareit/request/ItemRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.request; - -/** - * TODO Sprint add-item-requests. - */ -public class ItemRequest { -} diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java b/src/main/java/ru/practicum/shareit/request/ItemRequestController.java index 064e2e9c6..142eb0882 100644 --- a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java +++ b/src/main/java/ru/practicum/shareit/request/ItemRequestController.java @@ -1,12 +1,52 @@ package ru.practicum.shareit.request; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.request.dto.RequestDTO; +import ru.practicum.shareit.request.dto.RequestDTOWithItems; +import ru.practicum.shareit.request.service.RequestService; + +import javax.validation.constraints.Positive; +import javax.validation.constraints.PositiveOrZero; +import java.util.List; -/** - * TODO Sprint add-item-requests. - */ @RestController @RequestMapping(path = "/requests") +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@Slf4j +@Validated public class ItemRequestController { + private final RequestService requestService; + + @PostMapping + public RequestDTO addRequest(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestBody RequestDTO request) { + log.info("Добавление запроса на добавление вещи для пользователя {}", userId); + return requestService.add(userId, request); + } + + @GetMapping + public List getAllOwnRequest(@RequestHeader("X-Sharer-User-Id") Long userId) { + log.info("Просмотр всех запросов на добавление вещи для пользователя {}", userId); + return requestService.findAllByOwner(userId); + } + + @GetMapping("/all") + public List getAllRequest(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(defaultValue = "0") + @PositiveOrZero Integer from, + @RequestParam(name = "size", defaultValue = "1") + @Positive Integer size) { + log.info("Просмотр всех запросов на добавление вещи"); + return requestService.findAll(userId, from, size); + } + + @GetMapping("/{requestId}") + public RequestDTO getRequest(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long requestId) { + log.info("Просмотр запроса с id {}", requestId); + return requestService.findById(userId, requestId); + } } diff --git a/src/main/java/ru/practicum/shareit/request/RequestMapper.java b/src/main/java/ru/practicum/shareit/request/RequestMapper.java new file mode 100644 index 000000000..6e4cfdf36 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/RequestMapper.java @@ -0,0 +1,42 @@ +package ru.practicum.shareit.request; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.request.dto.RequestDTO; +import ru.practicum.shareit.request.dto.RequestDTOWithItems; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.UserMapper; + +import java.util.List; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class RequestMapper { + public static RequestDTO toRequestDto(ItemRequest itemRequest) { + RequestDTO requestDto = new RequestDTO(); + requestDto.setId(itemRequest.getId()); + requestDto.setDescription(itemRequest.getDescription()); + requestDto.setRequester(UserMapper.toUserToRequest(itemRequest.getRequester())); + requestDto.setCreated(itemRequest.getCreated()); + return requestDto; + } + + public static ItemRequest toItemRequest(RequestDTO requestDto) { + ItemRequest request = new ItemRequest(); + request.setId(requestDto.getId()); + request.setDescription(requestDto.getDescription()); + request.setRequester(UserMapper.toUser(requestDto.getRequester())); + request.setCreated(requestDto.getCreated()); + return request; + } + + public static RequestDTOWithItems toRequestForFindDto(ItemRequest itemRequest, List item) { + RequestDTOWithItems requestDto = new RequestDTOWithItems(); + requestDto.setId(itemRequest.getId()); + requestDto.setDescription(itemRequest.getDescription()); + requestDto.setRequester(UserMapper.toUserToRequest(itemRequest.getRequester())); + requestDto.setCreated(itemRequest.getCreated()); + requestDto.setItems(item); + return requestDto; + } +} diff --git a/src/main/java/ru/practicum/shareit/request/RequestRepository.java b/src/main/java/ru/practicum/shareit/request/RequestRepository.java new file mode 100644 index 000000000..a7311a240 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/RequestRepository.java @@ -0,0 +1,22 @@ +package ru.practicum.shareit.request; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import java.util.List; + +public interface RequestRepository extends JpaRepository { + + List findByRequesterOrderByCreatedDesc(User requester); + + @Query(nativeQuery = true, value = "SELECT * FROM REQUESTS" + + " WHERE REQUESTER_ID != ?1") + Page findAllBy(Long userId, Pageable pageable); + + List findAllByRequester_IdNot(Long userId, Pageable pageable); + +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java deleted file mode 100644 index 7b3ed5440..000000000 --- a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.request.dto; - -/** - * TODO Sprint add-item-requests. - */ -public class ItemRequestDto { -} diff --git a/src/main/java/ru/practicum/shareit/request/dto/RequestDTO.java b/src/main/java/ru/practicum/shareit/request/dto/RequestDTO.java new file mode 100644 index 000000000..8ec63dfa4 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/dto/RequestDTO.java @@ -0,0 +1,26 @@ +package ru.practicum.shareit.request.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.time.LocalDateTime; + +@Data +public class RequestDTO { + + private Long id; + + @NotBlank() + private String description; + + private User requester; + + private LocalDateTime created; + + @Data + public static class User { + private final long id; + private final String name; + } +} + diff --git a/src/main/java/ru/practicum/shareit/request/dto/RequestDTOWithItems.java b/src/main/java/ru/practicum/shareit/request/dto/RequestDTOWithItems.java new file mode 100644 index 000000000..05d4ea9be --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/dto/RequestDTOWithItems.java @@ -0,0 +1,13 @@ +package ru.practicum.shareit.request.dto; + +import lombok.Data; +import ru.practicum.shareit.item.dto.ItemDTO; + +import java.util.List; + +@Data +public class RequestDTOWithItems extends RequestDTO { + + private List items; + +} diff --git a/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java new file mode 100644 index 000000000..012e87d40 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java @@ -0,0 +1,29 @@ +package ru.practicum.shareit.request.model; + +import lombok.Data; +import ru.practicum.shareit.user.model.User; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Entity +@Table(name = "requests", schema = "public") +@Data +public class ItemRequest { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull() + @Column + private String description; + + @ManyToOne + @JoinColumn(name = "requester_id") + private User requester; + + @NotNull + private LocalDateTime created; +} diff --git a/src/main/java/ru/practicum/shareit/request/service/RequestService.java b/src/main/java/ru/practicum/shareit/request/service/RequestService.java new file mode 100644 index 000000000..fed049bec --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/service/RequestService.java @@ -0,0 +1,16 @@ +package ru.practicum.shareit.request.service; + +import ru.practicum.shareit.request.dto.RequestDTO; +import ru.practicum.shareit.request.dto.RequestDTOWithItems; + +import java.util.List; + +public interface RequestService { + RequestDTO add(Long userId, RequestDTO request); + + List findAllByOwner(Long userId); + + List findAll(Long userId, Integer page, Integer size); + + RequestDTOWithItems findById(Long userId, Long requestId); +} diff --git a/src/main/java/ru/practicum/shareit/request/service/RequestServiceImpl.java b/src/main/java/ru/practicum/shareit/request/service/RequestServiceImpl.java new file mode 100644 index 000000000..1ece187d2 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/service/RequestServiceImpl.java @@ -0,0 +1,102 @@ +package ru.practicum.shareit.request.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.item.ItemRepository; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.RequestMapper; +import ru.practicum.shareit.request.RequestRepository; +import ru.practicum.shareit.request.dto.RequestDTO; +import ru.practicum.shareit.request.dto.RequestDTOWithItems; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.UserRepository; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toList; + +@Service +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@Slf4j +public class RequestServiceImpl implements RequestService { + + private final UserRepository uRepository; + private final RequestRepository rRepository; + private final ItemRepository iRepository; + + + @Override + @Transactional + public RequestDTO add(Long userId, RequestDTO request) { + User user = uRepository.findById(userId).orElseThrow(() -> new NotFoundException("User not found")); + request.setCreated(LocalDateTime.now()); + request.setRequester(UserMapper.toUserToRequest(user)); + ItemRequest itemRequest = rRepository.save(RequestMapper.toItemRequest(request)); + return RequestMapper.toRequestDto(itemRequest); + } + + @Override + public List findAllByOwner(Long userId) { + User user = uRepository.findById(userId).orElseThrow(() -> new NotFoundException("User not found")); + List requests = new ArrayList<>(); + List itemRequests = rRepository.findByRequesterOrderByCreatedDesc(user); + for (ItemRequest request : itemRequests) { + List item = iRepository.findByRequest(request.getId()); + requests.add(RequestMapper.toRequestForFindDto(request, ItemMapper.mapToItemDto(item))); + } + return requests; + } + + @Override + public List findAll(Long userId, Integer page, Integer size) { + Pageable pageable = PageRequest.of(page, size); + List getAllRequests = new ArrayList<>(); + List itemRequests = rRepository.findAllByRequester_IdNot(userId, pageable); + Map> items = iRepository.findAllByRequestIdInAndAvailableTrue(itemRequests) + .stream() + .collect(groupingBy(Item::getRequestId, toList())); + for (ItemRequest request : itemRequests) { + RequestDTOWithItems itemRequestDtoResult; + List itemsToReturn; + if (!items.isEmpty()) { + itemsToReturn = items.get(request) + .stream() + .filter(item -> item.getRequestId().getId().equals(request.getId())) + .map(ItemMapper::toItemDto) + .collect(Collectors.toList()); + itemRequestDtoResult = RequestMapper.toRequestForFindDto(request, itemsToReturn); + getAllRequests.add(itemRequestDtoResult); + } else { + itemRequestDtoResult = RequestMapper.toRequestForFindDto(request, Collections.emptyList()); + getAllRequests.add(itemRequestDtoResult); + } + } + return getAllRequests; + } + + @Override + public RequestDTOWithItems findById(Long userId, Long requestId) { + uRepository.findById(userId).orElseThrow(() -> new NotFoundException("User not found")); + ItemRequest request = rRepository.findById(requestId) + .orElseThrow(() -> new NotFoundException("Request not found")); + List items = iRepository.findByRequest(requestId); + return RequestMapper.toRequestForFindDto(request, ItemMapper.mapToItemDto(items)); + } +} + diff --git a/src/main/java/ru/practicum/shareit/user/User.java b/src/main/java/ru/practicum/shareit/user/User.java deleted file mode 100644 index ae6e7f33e..000000000 --- a/src/main/java/ru/practicum/shareit/user/User.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.user; - -/** - * TODO Sprint add-controllers. - */ -public class User { -} diff --git a/src/main/java/ru/practicum/shareit/user/UserController.java b/src/main/java/ru/practicum/shareit/user/UserController.java index 03039b9da..ef070be8d 100644 --- a/src/main/java/ru/practicum/shareit/user/UserController.java +++ b/src/main/java/ru/practicum/shareit/user/UserController.java @@ -1,12 +1,51 @@ package ru.practicum.shareit.user; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.Create; +import ru.practicum.shareit.Update; +import ru.practicum.shareit.user.dto.UserDTO; +import ru.practicum.shareit.user.service.UserService; + +import java.util.Collection; -/** - * TODO Sprint add-controllers. - */ @RestController @RequestMapping(path = "/users") +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@Slf4j public class UserController { + private final UserService userService; + + @PostMapping + public UserDTO create(@Validated(Create.class) @RequestBody UserDTO user) { + log.info("Добавление нового пользователя"); + return userService.create(user); + } + + @PatchMapping("/{userId}") + public UserDTO update(@PathVariable Long userId, @Validated(Update.class) @RequestBody UserDTO user) { + log.info("Обновление данных о пользователе с id {}", userId); + return userService.update(userId, user); + } + + @DeleteMapping("/{id}") + public void delete(@PathVariable Long id) { + log.info("Удаление пользователя с id {}", id); + userService.delete(id); + } + + @GetMapping + public Collection getAll() { + log.info("Получение списка всех пользователей"); + return userService.getAll(); + } + + @GetMapping("/{id}") + public UserDTO get(@PathVariable Long id) { + log.info("Получение пользователя с id {}", id); + return userService.get(id); + } } diff --git a/src/main/java/ru/practicum/shareit/user/UserMapper.java b/src/main/java/ru/practicum/shareit/user/UserMapper.java new file mode 100644 index 000000000..bab13c425 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/UserMapper.java @@ -0,0 +1,78 @@ +package ru.practicum.shareit.user; + +import lombok.experimental.UtilityClass; +import ru.practicum.shareit.booking.dto.BookingDTOToReturn; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.item.dto.ItemDTOWithBookings; +import ru.practicum.shareit.request.dto.RequestDTO; +import ru.practicum.shareit.user.dto.UserDTO; +import ru.practicum.shareit.user.model.User; + +import java.util.ArrayList; +import java.util.List; + +@UtilityClass +public class UserMapper { + + public static UserDTO toUserDto(User user) { + UserDTO userDto = new UserDTO(); + userDto.setId(user.getId()); + userDto.setName(user.getName()); + userDto.setEmail(user.getEmail()); + return userDto; + } + + public static User toUser(UserDTO userDto) { + User user = new User(); + user.setId(userDto.getId()); + user.setName(userDto.getName()); + user.setEmail(userDto.getEmail()); + return user; + } + + public static User toUser(ItemDTOWithBookings.User user) { + User newUser = new User(); + newUser.setId(user.getId()); + newUser.setName(user.getName()); + return newUser; + } + + public static List mapToUserDto(Iterable users) { + List dtos = new ArrayList<>(); + for (User user : users) { + dtos.add(toUserDto(user)); + } + return dtos; + } + + public static ItemDTOWithBookings.User toUserToItemWithBookingsDto(User user) { + return new ItemDTOWithBookings.User(user.getId(), user.getName(), user.getEmail()); + } + + public static ItemDTO.User toUserToItemDto(User user) { + return new ItemDTO.User(user.getId(), user.getName(), user.getEmail()); + } + + public static List mapToUser(Iterable users) { + List dtos = new ArrayList<>(); + for (UserDTO user : users) { + dtos.add(toUser(user)); + } + return dtos; + } + + public static User toUser(RequestDTO.User userRequest) { + User user = new User(); + user.setId(userRequest.getId()); + user.setName(userRequest.getName()); + return user; + } + + public static RequestDTO.User toUserToRequest(User user) { + return new RequestDTO.User(user.getId(), user.getName()); + } + + public static BookingDTOToReturn.User toUserToBookingDTO(User user) { + return new BookingDTOToReturn.User(user.getId(), user.getName()); + } +} diff --git a/src/main/java/ru/practicum/shareit/user/UserRepository.java b/src/main/java/ru/practicum/shareit/user/UserRepository.java new file mode 100644 index 000000000..59324814d --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/UserRepository.java @@ -0,0 +1,7 @@ +package ru.practicum.shareit.user; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.shareit.user.model.User; + +public interface UserRepository extends JpaRepository { +} diff --git a/src/main/java/ru/practicum/shareit/user/dto/UserDTO.java b/src/main/java/ru/practicum/shareit/user/dto/UserDTO.java new file mode 100644 index 000000000..e44b1aae4 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/dto/UserDTO.java @@ -0,0 +1,22 @@ +package ru.practicum.shareit.user.dto; + +import lombok.Data; +import ru.practicum.shareit.Create; +import ru.practicum.shareit.Update; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; + +@Data +public class UserDTO { + + private long id; + + @NotBlank(groups = {Create.class}) + private String name; + + @Email(groups = {Update.class, Create.class}) + @NotEmpty(groups = {Create.class}) + private String email; +} diff --git a/src/main/java/ru/practicum/shareit/user/model/User.java b/src/main/java/ru/practicum/shareit/user/model/User.java new file mode 100644 index 000000000..e17f3894d --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/model/User.java @@ -0,0 +1,47 @@ +package ru.practicum.shareit.user.model; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.Hibernate; + +import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import java.util.Objects; + +@Entity +@Table(name = "users", schema = "public") +@Getter +@Setter +@ToString +@RequiredArgsConstructor +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @Column(nullable = false) + private String name; + + @Email + @NotBlank + @Column(nullable = false) + private String email; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; + User user = (User) o; + return id != null && Objects.equals(id, user.id); + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } +} diff --git a/src/main/java/ru/practicum/shareit/user/service/UserService.java b/src/main/java/ru/practicum/shareit/user/service/UserService.java new file mode 100644 index 000000000..6b6026a9e --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/service/UserService.java @@ -0,0 +1,17 @@ +package ru.practicum.shareit.user.service; + +import ru.practicum.shareit.user.dto.UserDTO; + +import java.util.Collection; + +public interface UserService { + UserDTO create(UserDTO userDto); + + UserDTO update(Long userId, UserDTO userDto); + + void delete(Long id); + + Collection getAll(); + + UserDTO get(Long id); +} diff --git a/src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java b/src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java new file mode 100644 index 000000000..5c893d478 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java @@ -0,0 +1,64 @@ +package ru.practicum.shareit.user.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.UserRepository; +import ru.practicum.shareit.user.dto.UserDTO; +import ru.practicum.shareit.user.model.User; + +import java.util.List; +import java.util.Optional; + +@Service +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@Transactional(readOnly = true) +public class UserServiceImpl implements UserService { + private final UserRepository repository; + + @Transactional + @Override + public UserDTO create(UserDTO userDto) { + User user = repository.save(UserMapper.toUser(userDto)); + return UserMapper.toUserDto(user); + } + + @Transactional + @Override + public UserDTO update(Long userId, UserDTO userDto) { + User user = repository.findById(userId) + .orElseThrow(() -> new NotFoundException("User not found")); + if (userDto.getName() != null && !userDto.getName().isBlank()) { + user.setName(userDto.getName()); + } + if (userDto.getEmail() != null && !userDto.getEmail().isBlank()) { + user.setEmail(userDto.getEmail()); + } + return UserMapper.toUserDto(user); + } + + @Transactional + @Override + public void delete(Long id) { + Optional user = repository.findById(id); + if (user.isEmpty()) { + throw new NotFoundException("User not found"); + } + repository.deleteById(id); + } + + @Override + public List getAll() { + return UserMapper.mapToUserDto(repository.findAll()); + } + + @Override + public UserDTO get(Long id) { + Optional user = Optional.ofNullable(repository.findById(id) + .orElseThrow(() -> new NotFoundException("User not found"))); + return UserMapper.toUserDto(user.get()); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c359e8d7a..dc7cf84ea 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,22 +1,18 @@ spring.jpa.hibernate.ddl-auto=none -spring.jpa.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect -spring.jpa.hibernate.show_sql=true - +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect +spring.jpa.properties.hibernate.format_sql=true spring.sql.init.mode=always -# TODO Append connection to DB - - - logging.level.org.springframework.orm.jpa=INFO logging.level.org.springframework.transaction=INFO logging.level.org.springframework.transaction.interceptor=TRACE logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG + +#--- +# TODO Append connection to DB #--- -spring.config.activate.on-profile=ci,test +#spring.config.activate.on-profile=ci,test spring.datasource.driverClassName=org.h2.Driver -spring.datasource.url=jdbc:h2:mem:shareit +spring.datasource.url=jdbc:h2:./db/shareit spring.datasource.username=test spring.datasource.password=test - -spring.h2.console.enabled=true \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 000000000..92654603d --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,62 @@ +DROP TABLE IF EXISTS comments; +DROP TABLE IF EXISTS bookings; +DROP TABLE IF EXISTS items; +DROP TABLE IF EXISTS requests; +DROP TABLE IF EXISTS users; + +CREATE TABLE IF NOT EXISTS users +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + name VARCHAR(100) NOT NULL, + email VARCHAR(320) NOT NULL, + CONSTRAINT pk_user PRIMARY KEY (id), + CONSTRAINT UQ_USER_EMAIL UNIQUE (email), + CONSTRAINT EMAIL_FORMAT CHECK (email LIKE '%@%.%' AND email NOT LIKE '@%' AND email NOT LIKE '%@%@%') +); + +CREATE TABLE IF NOT EXISTS requests +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + description VARCHAR(1000) NOT NULL, + requester_id BIGINT NOT NULL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + CONSTRAINT pk_requests PRIMARY KEY (id), + CONSTRAINT requester_id_foreign_key_user_id FOREIGN KEY (requester_id) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS items +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + name VARCHAR(100) NOT NULL, + description VARCHAR(512) NOT NULL, + available BOOLEAN NOT NULL, + owner_id BIGINT NOT NULL, + request_id BIGINT, + CONSTRAINT pk_item PRIMARY KEY (id), + CONSTRAINT owner_id_foreign_key_user_id FOREIGN KEY (owner_id) REFERENCES users (id), + CONSTRAINT request_id_foreign_key FOREIGN KEY (request_id) REFERENCES requests (id) +); + +CREATE TABLE IF NOT EXISTS bookings +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + start_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + end_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, + item_id BIGINT NOT NULL, + booker_id BIGINT NOT NULL, + status VARCHAR(100) NOT NULL, + CONSTRAINT pk_booking PRIMARY KEY (id), + CONSTRAINT item_foreign_key_booking_id FOREIGN KEY (item_id) REFERENCES items (id) +); + +CREATE TABLE IF NOT EXISTS comments +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + text VARCHAR(1000) NOT NULL, + item_id BIGINT NOT NULL, + author_id BIGINT NOT NULL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + CONSTRAINT pk_comments PRIMARY KEY (id), + CONSTRAINT author_id_foreign_key_user_id FOREIGN KEY (author_id) REFERENCES users (id), + CONSTRAINT item_foreign_key_comment_id FOREIGN KEY (item_id) REFERENCES items (id) +) \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/ShareItTests.java b/src/test/java/ru/practicum/shareit/ShareItTests.java index 4d79052f0..62804b450 100644 --- a/src/test/java/ru/practicum/shareit/ShareItTests.java +++ b/src/test/java/ru/practicum/shareit/ShareItTests.java @@ -1,13 +1,387 @@ package ru.practicum.shareit; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; 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.context.SpringBootTest; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener; +import ru.practicum.shareit.booking.dto.BookingDTO; +import ru.practicum.shareit.booking.dto.BookingDTOToReturn; +import ru.practicum.shareit.booking.model.Status; +import ru.practicum.shareit.booking.service.BookingService; +import ru.practicum.shareit.exception.BadRequestException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.exception.StatusBadRequestException; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.item.dto.ItemDTOWithBookings; +import ru.practicum.shareit.item.service.ItemService; +import ru.practicum.shareit.request.dto.RequestDTOWithItems; +import ru.practicum.shareit.request.service.RequestService; +import ru.practicum.shareit.user.dto.UserDTO; +import ru.practicum.shareit.user.service.UserService; + +import java.time.LocalDateTime; +import java.time.Month; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest +@AutoConfigureTestDatabase +@RequiredArgsConstructor(onConstructor_ = {@Autowired}) +@TestExecutionListeners({DirtiesContextBeforeModesTestExecutionListener.class}) +@Slf4j class ShareItTests { - @Test - void contextLoads() { - } + private final BookingService bookingService; + private final ItemService itemService; + private final RequestService requestService; + + private final UserService userService; + + @Test + void contextLoads() { + } + + @Test + void createUser() { + UserDTO userDTO = new UserDTO(); + userDTO.setId(1); + userDTO.setName("Aelin"); + userDTO.setEmail("aelin@whitethorn.com"); + + UserDTO user = userService.create(userDTO); + assertThat(user).isNotNull(); + assertThat(user.getId()).isEqualTo(1); + assertThat(user.getName()).isEqualTo("Aelin"); + assertThat(user.getEmail()).isEqualTo("aelin@whitethorn.com"); + } + + @Test + void getItem() { + ItemDTOWithBookings itemDTO = itemService.get(1L, 1L); + assertThat(itemDTO).isNotNull(); + assertThat(itemDTO.getId()).isEqualTo(1L); + assertThat(itemDTO.getName()).isEqualTo("Sword"); + assertThat(itemDTO.getDescription()).isEqualTo("For fights"); + assertThat(itemDTO.getAvailable()).isEqualTo(true); + } + + @Test + void getBookingWithEndBeforeStart() { + BookingDTO bDto = new BookingDTO(); + bDto.setBookerId(1L); + bDto.setId(1); + bDto.setStart(LocalDateTime.of(2023, Month.FEBRUARY, 13, 12, 29, 00)); + bDto.setEnd(LocalDateTime.of(2022, Month.FEBRUARY, 13, 12, 29, 00)); + bDto.setStatus(Status.WAITING); + bDto.setItemId(3L); + + final BadRequestException exception = Assertions.assertThrows( + BadRequestException.class, + () -> bookingService.add(1L, bDto)); + assertThat(exception.getMessage()).isEqualTo("Wrong date"); + } + + @Test + void bookingGet() { + BookingDTOToReturn booking = bookingService.get(2L, 4L); + assertThat(booking).isNotNull(); + assertThat(booking.getId()).isEqualTo(4L); + assertThat(booking.getBooker().getId()).isEqualTo(1); + assertThat(booking.getStatus()).isEqualTo(Status.WAITING); + assertThat(booking.getStart()).isEqualTo(LocalDateTime.parse("2023-11-11T12:32:59")); + } + + @Test + void bookingGetNoRights() { + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.get(2L, 1L)); + assertThat(exception.getMessage()).isEqualTo("No rights"); + } + + @Test + void getAllOwnItemTest() { + List items = itemService.getAllByOwner(1L, null, null); + assertThat(items).isNotEmpty(); + assertThat(items.size()).isEqualTo(1); + assertThat(items.get(0).getName()).isEqualTo("Knives"); + } + + @Test + void getAllOwnItemNotFoundUserTest() { + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> itemService.getAllByOwner(5L, null, null)); + assertThat(exception.getMessage()).isEqualTo("User not found"); + + } + + @Test + void getAllOwnItemFromOrSizeLessThanZeroTest() { + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> itemService.getAllByOwner(1L, -1, 0)); + + Assertions.assertEquals("/ by zero", + exception.getMessage()); + } + + @Test + void getAllOwnItemSizeEqualToZeroTest() { + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> itemService.getAllByOwner(1L, 1, 0)); + + Assertions.assertEquals("/ by zero", exception.getMessage()); + } + + @Test + void getItemsForRentTest() { + List items = itemService.getForRent("Sw", null, null); + assertThat(items).isNotEmpty(); + assertThat(items.size()).isEqualTo(1); + assertThat(items.get(0).getName()).isEqualTo("Sword"); + items = itemService.getForRent("fight", 0, 1); + assertThat(items).isNotEmpty(); + assertThat(items.size()).isEqualTo(1); + } + + @Test + void getItemForRentEqualToZeroTest() { + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> itemService.getForRent("S", 0, 0)); + + Assertions.assertEquals("/ by zero", exception.getMessage()); + + } + + @Test + void getItemsForRentFromOrSizeLessThanZeroTest() { + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> itemService.getForRent("F", -1, 0)); + + Assertions.assertEquals("/ by zero", + exception.getMessage()); + + } + + @Test + void getBookingByBookerStateAllTest() { + List bookings = bookingService.getByBooker(3L, + "ALL", null, null); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(2); + bookings = bookingService.getByBooker(3L, "ALL", null, null); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(2); + } + + @Test + void getBookingByBookerStateCurrentTest() { + List bookings = bookingService.getByBooker(3L, + "CURRENT", null, null); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(2); + } + + @Test + void getBookingByBookerStatePastTest() { + List bookings = bookingService.getByBooker(3L, + "PAST", null, null); + assertThat(bookings).isEmpty(); + } + + @Test + void getBookingByBookerStateFutureTest() { + List bookings = bookingService.getByBooker(2L, + "FUTURE", null, null); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(3); + } + + @Test + void getBookingByBookerStateWaitingTest() { + List bookings = bookingService.getByBooker(1L, + "WAITING", 0, 1); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(4); + } + + @Test + void getBookingsByBookerUnknownStatePageableTest() { + final StatusBadRequestException exception = Assertions.assertThrows( + StatusBadRequestException.class, + () -> bookingService.getByBooker(3L, "WRONG", 0, 1)); + + Assertions.assertEquals("Unknown state: UNSUPPORTED_STATUS", exception.getMessage()); + + } + + @Test + void getBookingsByBookerNotFoundUserTest() { + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.getByBooker(5L, null, 0, 1)); + + Assertions.assertEquals("No rights", exception.getMessage()); + + } + + @Test + void getBookingsByBookerSizeOrPageLessZeroTest() { + final IllegalArgumentException exception = Assertions.assertThrows( + IllegalArgumentException.class, + () -> bookingService.getByBooker(3L, null, -1, 1)); + + Assertions.assertEquals("Page index must not be less than zero", + exception.getMessage()); + + } + + @Test + void getBookingsByBookerSizeEqualZeroTest() { + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> bookingService.getByBooker(3L, null, 0, 0)); + + Assertions.assertEquals("/ by zero", exception.getMessage()); + + } + + @Test + void getBookingsByOwnerNotFoundUserTest() { + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.getByOwner(8L, null, 0, 1)); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void getBookingsByOwnerSizeOrPageLessZeroTest() { + final IllegalArgumentException exception = Assertions.assertThrows( + IllegalArgumentException.class, + () -> bookingService.getByOwner(1L, null, -1, 1)); + + Assertions.assertEquals("Page index must not be less than zero", + exception.getMessage()); + + } + + @Test + void getBookingsByOwnerByStateAllTest() { + List bookings = bookingService.getByOwner(1L, + "ALL", 0, 1); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(2); + bookings = bookingService.getByOwner(1L, "ALL", 0, 1); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(2); + } + + @Test + void getBookingsByOwnerByStatePastTest() { + List bookings = bookingService.getByOwner(3L, + "PAST", 0, 1); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(1); + } + + @Test + void getBookingsByOwnerByStateCurrentTest() { + List bookings = bookingService.getByOwner(1L, + "CURRENT", 0, 1); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(2); + } + + @Test + void getBookingsByOwnerByStateFutureTest() { + List bookings = bookingService.getByOwner(2L, + "FUTURE", 0, 1); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(4); + } + + @Test + void getBookingsByOwnerByStateWaitingOrRejectedTest() { + List bookings = bookingService.getByOwner(2L, + "WAITING", 0, 1); + assertThat(bookings).isNotEmpty(); + assertThat(bookings.size()).isEqualTo(1); + assertThat(bookings.get(0).getId()).isEqualTo(4); + } + + @Test + void getAllOwnRequestTest() { + List requests = requestService.findAllByOwner(3L); + assertThat(requests).isNotEmpty(); + assertThat(requests.size()).isEqualTo(1); + assertThat(requests.get(0).getId()).isEqualTo(3); + } + + @Test + void findAllOwnRequestsNotFoundUserTest() { + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> requestService.findAllByOwner(5L)); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void findAllRequestsTest() { + List requests = requestService.findAll(1L, 0, 1); + assertThat(requests).isNotEmpty(); + assertThat(requests.size()).isEqualTo(1); + assertThat(requests.get(0).getId()).isEqualTo(2); + } + + @Test + void findAllRequestsSizeOrPageLessZeroTest() { + final IllegalArgumentException exception = Assertions.assertThrows( + IllegalArgumentException.class, + () -> requestService.findAll(1L, 1, -1)); + + Assertions.assertEquals("Page size must not be less than one", + exception.getMessage()); + } + + @Test + void findAllRequestsSizeEqualZeroTest() { + final IllegalArgumentException exception = Assertions.assertThrows( + IllegalArgumentException.class, + () -> requestService.findAll(1L, 1, 0)); + + } + + @Test + void findRequestById() { + RequestDTOWithItems request = requestService.findById(1L,1L); + assertThat(request).isNotNull(); + assertThat(request.getId()).isEqualTo(1); + assertThat(request.getRequester().getId()).isEqualTo(1); + assertThat(request.getDescription()).isEqualTo("waiting for fight"); + assertThat(request.getCreated()).isEqualTo("2023-02-11T19:00:01"); + } + } diff --git a/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java b/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java new file mode 100644 index 000000000..27a791c53 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java @@ -0,0 +1,210 @@ +package ru.practicum.shareit.booking; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.servlet.MockMvc; +import ru.practicum.shareit.booking.dto.BookingDTOToReturn; +import ru.practicum.shareit.booking.model.Status; +import ru.practicum.shareit.booking.service.BookingServiceImpl; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@WebMvcTest(controllers = BookingController.class) +class BookingControllerTest { + + private final BookingDTOToReturn bookingDto = new BookingDTOToReturn(); + private final Item item = new Item(); + private final User user = new User(); + @Autowired + ObjectMapper mapper; + @MockBean + BookingServiceImpl bookingService; + @Autowired + private MockMvc mvc; + + @Test + void addBookingControllerTest() throws Exception { + addItem(); + addBookingDto(); + + when(bookingService.add(Mockito.anyLong(), any())) + .thenReturn(bookingDto); + + mvc.perform(post("/bookings") + .header("X-Sharer-User-Id", 4L) + .content(mapper.writeValueAsString(bookingDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(bookingDto.getId()), Long.class)) + .andExpect(jsonPath("$.start", is(bookingDto.getStart().toString()))) + .andExpect(jsonPath("$.booker.id", is((int)bookingDto.getBooker().getId()))) + .andExpect(jsonPath("$.booker.name", is(bookingDto.getBooker().getName()))) + .andExpect(jsonPath("$.end", is(bookingDto.getEnd().toString()))) + .andExpect(jsonPath("$.item.id", is((int) bookingDto.getItem().getId()))) + .andExpect(jsonPath("$.item.name", is(bookingDto.getItem().getName()))) + .andExpect(jsonPath("$.status", is(bookingDto.getStatus().toString()))); + + } + + @Test + void updateStatusBookingControllerTest() throws Exception { + addItem(); + addBookingDto(); + + when(bookingService.update(Mockito.any(), Mockito.anyLong(), Mockito.anyBoolean())) + .thenReturn(bookingDto); + + mvc.perform(patch("/bookings/2") + .header("X-Sharer-User-Id", 1L) + .param("approved", String.valueOf(true)) + .content(mapper.writeValueAsString(bookingDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(bookingDto.getId()), Long.class)) + .andExpect(jsonPath("$.start", is(bookingDto.getStart().toString()))) + .andExpect(jsonPath("$.booker.id", is((int)bookingDto.getBooker().getId()))) + .andExpect(jsonPath("$.booker.name", is(bookingDto.getBooker().getName()))) + .andExpect(jsonPath("$.end", is(bookingDto.getEnd().toString()))) + .andExpect(jsonPath("$.item.id", is((int) bookingDto.getItem().getId()))) + .andExpect(jsonPath("$.item.name", is(bookingDto.getItem().getName()))) + .andExpect(jsonPath("$.status", is(bookingDto.getStatus().toString()))); + } + + @Test + void getBookingControllerTest() throws Exception { + addItem(); + addBookingDto(); + + when(bookingService.get(Mockito.anyLong(), Mockito.anyLong())) + .thenReturn(bookingDto); + + mvc.perform(get("/bookings/2") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(bookingDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(bookingDto.getId()), Long.class)) + .andExpect(jsonPath("$.start", is(bookingDto.getStart().toString()))) + .andExpect(jsonPath("$.booker.id", is((int)bookingDto.getBooker().getId()))) + .andExpect(jsonPath("$.booker.name", is(bookingDto.getBooker().getName()))) + .andExpect(jsonPath("$.end", is(bookingDto.getEnd().toString()))) + .andExpect(jsonPath("$.item.id", is((int) bookingDto.getItem().getId()))) + .andExpect(jsonPath("$.item.name", is(bookingDto.getItem().getName()))) + .andExpect(jsonPath("$.status", is(bookingDto.getStatus().toString()))); + } + + @Test + void findBookingByBookerControllerTest() throws Exception { + addItem(); + addBookingDto(); + List bookings = new ArrayList<>(); + bookings.add(bookingDto); + + when(bookingService.getByBooker(Mockito.anyLong(), Mockito.anyString(), any(), any())) + .thenReturn(bookings); + + mvc.perform(get("/bookings") + .header("X-Sharer-User-Id", 4L) + .param("state", "ALL") + .content(mapper.writeValueAsString(bookingDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id", is(bookingDto.getId()), Long.class)) + .andExpect(jsonPath("$[0].start", is(bookingDto.getStart().toString()))) + .andExpect(jsonPath("$[0].booker.id", is((int)bookingDto.getBooker().getId()))) + .andExpect(jsonPath("$[0].booker.name", is(bookingDto.getBooker().getName()))) + .andExpect(jsonPath("$[0].end", is(bookingDto.getEnd().toString()))) + .andExpect(jsonPath("$[0].item.id", is((int) bookingDto.getItem().getId()))) + .andExpect(jsonPath("$[0].item.name", is(bookingDto.getItem().getName()))) + .andExpect(jsonPath("$[0].status", is(bookingDto.getStatus().toString()))); + } + + @Test + void findBookingByOwnerControllerTest() throws Exception { + addItem(); + addBookingDto(); + List bookings = new ArrayList<>(); + bookings.add(bookingDto); + + when(bookingService.getByOwner(Mockito.anyLong(), Mockito.anyString(), any(), any())) + .thenReturn(bookings); + + mvc.perform(get("/bookings/owner") + .header("X-Sharer-User-Id", 1L) + .param("state", "ALL") + .content(mapper.writeValueAsString(bookingDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id", is(bookingDto.getId()), Long.class)) + .andExpect(jsonPath("$[0].start", is(bookingDto.getStart().toString()))) + .andExpect(jsonPath("$[0].booker.id", is((int)bookingDto.getBooker().getId()))) + .andExpect(jsonPath("$[0].booker.name", is(bookingDto.getBooker().getName()))) + .andExpect(jsonPath("$[0].end", is(bookingDto.getEnd().toString()))) + .andExpect(jsonPath("$[0].item.id", is((int) bookingDto.getItem().getId()))) + .andExpect(jsonPath("$[0].item.name", is(bookingDto.getItem().getName()))) + .andExpect(jsonPath("$[0].status", is(bookingDto.getStatus().toString()))); + } + + private void addItem() { + addUser(); + item.setId(1L); + item.setName("Sword"); + item.setOwner(user); + item.setAvailable(true); + item.setDescription("For fight"); + } + + private void addUser() { + user.setId(1L); + user.setName("Aelin"); + user.setEmail("aelin@whitethorn.com"); + } + + private void addBookingDto() { + User booker = new User(); + booker.setId(4L); + booker.setName("Rowan"); + booker.setEmail("rowan@whitethorn.com"); + bookingDto.setId(2L); + bookingDto.setItem(ItemMapper.toItemToBookingDTO(item)); + bookingDto.setStatus(Status.WAITING); + bookingDto.setBooker(UserMapper.toUserToBookingDTO(booker)); + String date = "2023-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + bookingDto.setStart(localdatetime); + date = "2023-11-26T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingDto.setEnd(localdatetime); + } +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/booking/BookingRepositoryTest.java b/src/test/java/ru/practicum/shareit/booking/BookingRepositoryTest.java new file mode 100644 index 000000000..d8b469ef9 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/booking/BookingRepositoryTest.java @@ -0,0 +1,483 @@ +package ru.practicum.shareit.booking; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.Status; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@Slf4j +class BookingRepositoryTest { + + private final User user = new User(); + private final Item item = new Item(); + private final ItemRequest request = new ItemRequest(); + private final Booking bookingOne = new Booking(); + private final Booking bookingTwo = new Booking(); + private final List bookingsList = new ArrayList<>(); + @Autowired + private TestEntityManager em; + @Autowired + private BookingRepository bookingRepository; + + @Test + void findByItemOrderByStartDescTest() { + addItem(); + addBookingOne(); + addUser(); + addBookingTwo(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + booking = em.persist(bookingTwo); + bookingsList.add(booking); + + List bookings = bookingRepository.findByItemOrderByStartDesc(item); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookerAndStatusOrderByStartDescTest() { + addItem(); + addBookingOne(); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + + List bookings = bookingRepository.findByBookerAndStatusOrderByStartDesc(bookingOne.getBooker(), + Status.WAITING); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void testFindByBookerAndStatusOrderByStartDesc() { + addItem(); + addBookingOne(); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + Pageable pageable = PageRequest.of(0, 1); + + Page bookingsPage = bookingRepository.findByBookerAndStatusOrderByStartDesc(bookingOne.getBooker(), + Status.WAITING, pageable); + List bookings = bookingsPage.getContent(); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookerOrderByStartDescTest() { + addItem(); + addBookingOne(); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + + List bookings = bookingRepository.findByBookerOrderByStartDesc(bookingOne.getBooker()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void testFindByBookerOrderByStartDesc() { + addItem(); + addBookingOne(); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + Pageable pageable = PageRequest.of(0, 1); + + Page bookingsPage = bookingRepository.findByBookerOrderByStartDesc(bookingOne.getBooker(), + pageable); + List bookings = bookingsPage.getContent(); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookerAndStartAfterOrderByStartDesc() { + addItem(); + addBookingOne(); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + + List bookings = bookingRepository.findByBookerAndStartAfterOrderByStartDesc(bookingOne.getBooker(), + LocalDateTime.now()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void testFindByBookerAndStartAfterOrderByStartDesc() { + addItem(); + addBookingOne(); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + Pageable pageable = PageRequest.of(0, 1); + + Page bookingsPage = bookingRepository.findByBookerAndStartAfterOrderByStartDesc(bookingOne.getBooker(), + LocalDateTime.now(), pageable); + List bookings = bookingsPage.getContent(); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookerAndStartBeforeAndEndAfterOrderByStartDescTest() { + addItem(); + addBookingOne(); + String date = "2021-11-21T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + bookingOne.setStart(localdatetime); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + + List bookings = bookingRepository.findByBookerAndStartBeforeAndEndAfterOrderByStartDesc( + bookingOne.getBooker(), LocalDateTime.now(), LocalDateTime.now()); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void testFindByBookerAndStartBeforeAndEndAfterOrderByStartDesc() { + addItem(); + addBookingOne(); + String date = "2021-11-21T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + bookingOne.setStart(localdatetime); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + + Pageable pageable = PageRequest.of(0, 1); + + Page bookingsPage = bookingRepository.findByBookerAndStartBeforeAndEndAfterOrderByStartDesc( + bookingOne.getBooker(), LocalDateTime.now(), LocalDateTime.now(), pageable); + + List bookings = bookingsPage.getContent(); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookerAndStartBeforeAndEndBeforeOrderByStartDescTest() { + addItem(); + addBookingOne(); + String date = "2021-11-21T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + bookingOne.setStart(localdatetime); + date = "2021-11-23T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingOne.setEnd(localdatetime); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + + List bookings = bookingRepository.findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc( + bookingOne.getBooker(), LocalDateTime.now(), LocalDateTime.now()); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void testFindByBookerAndStartBeforeAndEndBeforeOrderByStartDesc() { + addItem(); + addBookingOne(); + String date = "2021-11-21T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + bookingOne.setStart(localdatetime); + date = "2021-11-23T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingOne.setEnd(localdatetime); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + + Pageable pageable = PageRequest.of(0, 1); + + Page bookingsPage = bookingRepository.findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc( + bookingOne.getBooker(), LocalDateTime.now(), LocalDateTime.now(), pageable); + + List bookings = bookingsPage.getContent(); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByItemAndBookerAndStartBeforeAndEndBeforeTest() { + addItem(); + addBookingOne(); + String date = "2021-11-21T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + bookingOne.setStart(localdatetime); + date = "2021-11-23T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingOne.setEnd(localdatetime); + addUser(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + + List bookings = bookingRepository.findByItemAndBookerAndStartBeforeAndEndBefore(item, + bookingOne.getBooker(), LocalDateTime.now(), LocalDateTime.now()); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookingForOwnerWithPastTest() { + addUser(); + addItemWithoutId(); + em.persist(item); + String date = "2021-11-21T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + addBookingOne(); + bookingOne.setStart(localdatetime); + date = "2021-11-25T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingOne.setEnd(localdatetime); + addBookingTwo(); + date = "2022-10-25T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingTwo.setStart(localdatetime); + date = "2022-10-27T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingTwo.setEnd(localdatetime); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + booking = em.persist(bookingTwo); + bookingsList.add(booking); + + List bookings = bookingRepository.findByOwnerAndPast(1L, LocalDateTime.now()); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(1).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookingForOwnerWithPastWithPageableTest() { + Pageable pageable = PageRequest.of(0, 2); + addUser(); + addItemWithoutId(); + em.persist(item); + String date = "2021-11-21T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + addBookingOne(); + bookingOne.setStart(localdatetime); + date = "2021-11-25T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingOne.setEnd(localdatetime); + addBookingTwo(); + date = "2022-10-25T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingTwo.setStart(localdatetime); + date = "2022-10-27T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingTwo.setEnd(localdatetime); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + booking = em.persist(bookingTwo); + bookingsList.add(booking); + + List bookings = bookingRepository.findByOwnerAndPast(1L, LocalDateTime.now(), pageable); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(1).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookingForOwnerWithFutureTest() { + addUser(); + addItemWithoutId(); + em.persist(item); + addBookingOne(); + addBookingTwo(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + booking = em.persist(bookingTwo); + bookingsList.add(0, booking); + + List bookings = bookingRepository.findByUserAndFuture(1L, LocalDateTime.now()); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookingForOwnerWithFutureWithPageableTest() { + Pageable pageable = PageRequest.of(0, 2); + addUser(); + addItemWithoutId(); + em.persist(item); + addBookingOne(); + addBookingTwo(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + booking = em.persist(bookingTwo); + bookingsList.add(booking); + + List bookings = bookingRepository.findByUserAndFuture(1L, LocalDateTime.now(), pageable); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookingForOwnerWithAllTest() { + addUser(); + addItemWithoutId(); + em.persist(item); + addBookingOne(); + addBookingTwo(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + booking = em.persist(bookingTwo); + bookingsList.add(0, booking); + + List bookings = bookingRepository.findByOwnerAll(1L); + log.info(bookings.toString()); + log.info(bookingsList.toString()); + assertThat(bookingsList.get(0)).isEqualTo(bookings.get(0)); + } + + @Test + void findByBookingForOwnerWithAllWithPageableTest() { + Pageable pageable = PageRequest.of(0, 2); + addUser(); + addItemWithoutId(); + em.persist(item); + addBookingOne(); + addBookingTwo(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + booking = em.persist(bookingTwo); + bookingsList.add(booking); + + List bookings = bookingRepository.findByOwnerAll(1L, pageable); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookingForOwnerWithWaitingOrRejectedTest() { + addUser(); + addItemWithoutId(); + em.persist(item); + addBookingOne(); + addBookingTwo(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + booking = em.persist(bookingTwo); + bookingsList.add(0, booking); + + List bookings = bookingRepository.findByOwnerAndByStatus(1L, Status.WAITING); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + @Test + void findByBookingForOwnerWithWaitingOrRejectedWithPageableTest() { + Pageable pageable = PageRequest.of(0, 2); + addUser(); + addItemWithoutId(); + em.persist(item); + addBookingOne(); + addBookingTwo(); + Booking booking = em.persist(bookingOne); + bookingsList.add(booking); + booking = em.persist(bookingTwo); + bookingsList.add(booking); + + List bookings = bookingRepository.findByOwnerAndByStatus(1L, "WAITING", + pageable); + assertThat(bookingsList.size()).isEqualTo(bookings.size()); + assertThat(bookingsList.get(0).getId()).isEqualTo(bookings.get(0).getId()); + } + + private void addItem() { + addRequest(); + item.setId(1); + item.setName("Sword"); + item.setOwner(user); + item.setAvailable(true); + item.setDescription("For fights"); + item.setRequestId(request); + } + + private void addItemWithoutId() { + addRequest(); + item.setName("Sword"); + item.setOwner(user); + item.setAvailable(true); + item.setDescription("For fights"); + item.setRequestId(request); + } + + private void addUser() { + user.setId(1L); + user.setName("Aelin"); + user.setEmail("aelin@whitethorn.com"); + } + + private void addRequest() { + User requester = new User(); + requester.setId(2L); + requester.setName("Rowan"); + requester.setEmail("rowan@whitethorn.com"); + request.setId(1L); + request.setRequester(requester); + request.setDescription("waiting for fight"); + request.setCreated(LocalDateTime.now()); + } + + private void addBookingOne() { + User user1 = new User(); + user1.setId(2L); + user1.setName("Rowan"); + user1.setEmail("rowan@whitethorn.com"); + bookingOne.setBooker(user1); + bookingOne.setItem(item); + String date = "2024-11-20T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + bookingOne.setStart(localdatetime); + date = "2024-11-25T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingOne.setEnd(localdatetime); + bookingOne.setStatus(Status.WAITING); + } + + private void addBookingTwo() { + User booker = new User(); + booker.setId(3L); + booker.setName("Dorin"); + booker.setEmail("dorian@havilliard.com"); + bookingTwo.setStatus(Status.WAITING); + String date = "2023-11-21T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + bookingTwo.setStart(localdatetime); + date = "2023-11-22T18:08:54"; + localdatetime = LocalDateTime.parse(date); + bookingTwo.setEnd(localdatetime); + bookingTwo.setBooker(booker); + bookingTwo.setItem(item); + } + + @AfterEach + private void delete() { + bookingRepository.deleteAll(); + bookingsList.clear(); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoForItemTest.java b/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoForItemTest.java new file mode 100644 index 000000000..8553ff04e --- /dev/null +++ b/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoForItemTest.java @@ -0,0 +1,32 @@ +package ru.practicum.shareit.booking.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class BookingDtoForItemTest { + @Autowired + private JacksonTester json; + + @Test + void testBookingDto() throws Exception { + BookingDTOForItem bookingDto = new BookingDTOForItem(); + bookingDto.setId(1); + bookingDto.setBookerId(1L); + bookingDto.setDateTime(LocalDateTime.parse("2017-10-19T23:50:50")); + + JsonContent result = json.write(bookingDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(result).extractingJsonPathValue("$.dateTime").isEqualTo("2017-10-19T23:50:50"); + assertThat(result).extractingJsonPathValue("$.bookerId").isEqualTo(1); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java b/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java new file mode 100644 index 000000000..713847265 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java @@ -0,0 +1,41 @@ +package ru.practicum.shareit.booking.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; +import ru.practicum.shareit.booking.model.Status; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class BookingDtoTest { + @Autowired + private JacksonTester json; + + @Test + void testBookingDto() throws Exception { + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + BookingDTO bookingDto = new BookingDTO(); + bookingDto.setId(1); + bookingDto.setItemName("Sword"); + bookingDto.setStatus(Status.WAITING); + bookingDto.setStart(localdatetime); + localdatetime = LocalDateTime.parse(date); + bookingDto.setEnd(localdatetime); + bookingDto.setBookerId(1L); + + JsonContent result = json.write(bookingDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.itemName").isEqualTo("Sword"); + assertThat(result).extractingJsonPathValue("$.status").isEqualTo("WAITING"); + assertThat(result).extractingJsonPathValue("$.start").isEqualTo("2017-10-19T23:50:50"); + assertThat(result).extractingJsonPathValue("$.end").isEqualTo("2017-10-19T23:50:50"); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoToReturnTest.java b/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoToReturnTest.java new file mode 100644 index 000000000..5e730436a --- /dev/null +++ b/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoToReturnTest.java @@ -0,0 +1,47 @@ +package ru.practicum.shareit.booking.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; +import ru.practicum.shareit.booking.model.Status; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class BookingDtoToReturnTest { + @Autowired + private JacksonTester json; + + private final BookingDTOToReturn.User user = new BookingDTOToReturn.User(2L, "Rowan"); + private final BookingDTOToReturn.Item item = new BookingDTOToReturn.Item(1L, "Sword"); + + @Test + void testBookingDto() throws Exception { + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + BookingDTOToReturn bookingDto = new BookingDTOToReturn(); + bookingDto.setId(1); + bookingDto.setItem(item); + bookingDto.setStatus(Status.WAITING); + bookingDto.setStart(localdatetime); + localdatetime = LocalDateTime.parse(date); + bookingDto.setEnd(localdatetime); + bookingDto.setBooker(user); + + JsonContent result = json.write(bookingDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(result).extractingJsonPathValue("$.item.id").isEqualTo(1); + assertThat(result).extractingJsonPathValue("$.item.name").isEqualTo("Sword"); + assertThat(result).extractingJsonPathValue("$.status").isEqualTo("WAITING"); + assertThat(result).extractingJsonPathValue("$.start").isEqualTo("2017-10-19T23:50:50"); + assertThat(result).extractingJsonPathValue("$.end").isEqualTo("2017-10-19T23:50:50"); + assertThat(result).extractingJsonPathValue("$.booker.id").isEqualTo(2); + assertThat(result).extractingJsonPathValue("$.booker.name").isEqualTo("Rowan"); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/booking/service/BookingServiceTest.java b/src/test/java/ru/practicum/shareit/booking/service/BookingServiceTest.java new file mode 100644 index 000000000..e5c97c3fc --- /dev/null +++ b/src/test/java/ru/practicum/shareit/booking/service/BookingServiceTest.java @@ -0,0 +1,1460 @@ +package ru.practicum.shareit.booking.service; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.booking.BookingMapper; +import ru.practicum.shareit.booking.BookingRepository; +import ru.practicum.shareit.booking.dto.BookingDTOToReturn; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.Status; +import ru.practicum.shareit.exception.BadRequestException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.exception.StatusBadRequestException; +import ru.practicum.shareit.item.ItemRepository; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.service.ItemServiceImpl; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.UserRepository; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.service.UserServiceImpl; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@ExtendWith(MockitoExtension.class) +@Slf4j +class BookingServiceTest { + + private final Booking booking = new Booking(); + private final User user = new User(); + private final ItemRequest request = new ItemRequest(); + private final Item item = new Item(); + @InjectMocks + BookingServiceImpl bookingService; + @Mock + ItemRepository itemRepository; + @Mock + UserRepository userRepository; + @Mock + BookingRepository bookingRepository; + + @InjectMocks + UserServiceImpl userService; + + @InjectMocks + ItemServiceImpl itemService; + + @Test + void addBookingTest() { + addBooking(); + addRequest(); + addUser(); + addItem(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of((item))); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.save(any())) + .thenReturn(booking); + + Optional bookingDto = Optional.ofNullable(bookingService.add(3L, + BookingMapper.toBookingDto(booking))); + + assertThat(bookingDto) + .isPresent() + .hasValueSatisfying(addBookingTest -> { + assertThat(addBookingTest).hasFieldOrPropertyWithValue("id", booking.getId()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("item", + ItemMapper.toItemToBookingDTO(booking.getItem())); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("booker", + UserMapper.toUserToBookingDTO(booking.getBooker())); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("status", booking.getStatus()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("start", booking.getStart()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("end", booking.getEnd()); + } + ); + } + + @Test + void addBookingStartEqualsEnd() { + addBooking(); + addUser(); + addItem(); + booking.setEnd(LocalDateTime.parse("2017-10-19T23:50:50")); + booking.setStart((LocalDateTime.parse("2017-10-19T23:50:50"))); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final BadRequestException exception = Assertions.assertThrows( + BadRequestException.class, + () -> bookingService.add(2L, BookingMapper.toBookingDto(booking))); + + Assertions.assertEquals("Wrong date", + exception.getMessage()); + } + + @Test + void addBookingUserNotFoundTest() { + addBooking(); + addUser(); + addItem(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.add(2L, BookingMapper.toBookingDto(booking))); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void addBookingGetAvailableFalseTest() { + addBooking(); + addUser(); + addItem(); + item.setAvailable(false); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final BadRequestException exception = Assertions.assertThrows( + BadRequestException.class, + () -> bookingService.add(2L, BookingMapper.toBookingDto(booking))); + + Assertions.assertEquals("You can not book this item", exception.getMessage()); + } + + @Test + void addBookingItemNotFoundTest() { + addBooking(); + addUser(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.add(2L, BookingMapper.toBookingDto(booking))); + + Assertions.assertEquals("Item not found", exception.getMessage()); + } + + @Test + void addBookingOwnerEqualsBookerTest() { + addBooking(); + addUser(); + addItem(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.add(1L, BookingMapper.toBookingDto(booking))); + + Assertions.assertEquals("You cannot book your item", exception.getMessage()); + } + + @Test + void addBookingNotValidEndTest() { + addBooking(); + addUser(); + addItem(); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setEnd(localdatetime); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final BadRequestException exception = Assertions.assertThrows( + BadRequestException.class, + () -> bookingService.add(2L, BookingMapper.toBookingDto(booking))); + + Assertions.assertEquals("Wrong date", + exception.getMessage()); + } + + @Test + void addBookingNotValidStartTest() { + addBooking(); + addUser(); + addItem(); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final BadRequestException exception = Assertions.assertThrows( + BadRequestException.class, + () -> bookingService.add(2L, BookingMapper.toBookingDto(booking))); + + Assertions.assertEquals("Wrong date", + exception.getMessage()); + } + + @Test + void addBookingEndIsBeforeStartTest() { + addBooking(); + addUser(); + addItem(); + booking.setStart(LocalDateTime.parse("2017-10-19T23:50:50")); + booking.setEnd(LocalDateTime.parse("2016-10-19T23:50:50")); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final BadRequestException exception = Assertions.assertThrows( + BadRequestException.class, + () -> bookingService.add(2L, BookingMapper.toBookingDto(booking))); + + Assertions.assertEquals("Wrong date", + exception.getMessage()); + } + + @Test + void updateStatusBookingApprovedTest() { + addUser(); + addItem(); + addBooking(); + + assertThat(Optional.of(booking)) + .isPresent() + .hasValueSatisfying(addBookingTest -> { + assertThat(addBookingTest).hasFieldOrPropertyWithValue("id", booking.getId()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("item", booking.getItem()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("booker", booking.getBooker()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("status", booking.getStatus()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("start", booking.getStart()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("end", booking.getEnd()); + } + ); + } + + @Test + void updateStatusBookingRejectedTest() { + addUser(); + addItem(); + addBooking(); + + assertThat(Optional.of(booking)) + .isPresent() + .hasValueSatisfying(addBookingTest -> { + assertThat(addBookingTest).hasFieldOrPropertyWithValue("id", booking.getId()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("item", booking.getItem()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("booker", booking.getBooker()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("status", booking.getStatus()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("start", booking.getStart()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("end", booking.getEnd()); + } + ); + } + + @Test + void updateStatusBookingNotFoundTest() { + Mockito + .when(bookingRepository.getReferenceById(Mockito.anyLong())) + .thenReturn(null); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.update(1L, 2L, false)); + + Assertions.assertEquals("Booking not found", exception.getMessage()); + + } + + @Test + void updateStatusNoAccessForUserTest() { + addUser(); + addItem(); + addBooking(); + + Mockito + .when(bookingRepository.getReferenceById(Mockito.anyLong())) + .thenReturn(booking); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.update(3L, 1L, false)); + + Assertions.assertEquals("No rights", exception.getMessage()); + + } + + @Test + void updateStatusBookingBadRequestTest() { + addUser(); + addItem(); + addBooking(); + booking.setStatus(Status.APPROVED); + + Mockito + .when(bookingRepository.getReferenceById(Mockito.anyLong())) + .thenReturn(booking); + + final BadRequestException exception = Assertions.assertThrows( + BadRequestException.class, + () -> bookingService.update(1L, 1L, false)); + + Assertions.assertEquals("Status has already been changed", exception.getMessage()); + + } + + @Test + void getBookingTest() { + addBooking(); + addRequest(); + addItem(); + addUser(); + + Mockito + .when(bookingRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(booking)); + + Optional bookingDto = Optional.ofNullable(bookingService.get(1L, 1L)); + + assertThat(bookingDto) + .isPresent() + .hasValueSatisfying(addBookingTest -> { + assertThat(addBookingTest).hasFieldOrPropertyWithValue("id", booking.getId()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("item", + ItemMapper.toItemToBookingDTO(booking.getItem())); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("booker", + UserMapper.toUserToBookingDTO(booking.getBooker())); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("status", booking.getStatus()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("start", booking.getStart()); + assertThat(addBookingTest).hasFieldOrPropertyWithValue("end", booking.getEnd()); + } + ); + } + + @Test + void getBookingNotFoundUserTest() { + addUser(); + addItem(); + addBooking(); + + Mockito + .when(bookingRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(booking)); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.get(5L, 1L)); + + Assertions.assertEquals("No rights", exception.getMessage()); + } + + @Test + void getBookingNotFoundTest() { + Mockito + .when(bookingRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.get(1L, 1L)); + + Assertions.assertEquals("Booking not found", exception.getMessage()); + } + + @Test + void getBookingByBookerALLTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerOrderByStartDesc(any())) + .thenReturn(bookingList); + + List bookings = bookingService.getByBooker(3L, "ALL", + null, null); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerALLWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + Page page = new PageImpl<>(bookingList); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerOrderByStartDesc(any(), any())) + .thenReturn(page); + + List bookings = bookingService.getByBooker(3L, "ALL", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerOrderByStartDesc(any())) + .thenReturn(bookingList); + + List bookings = bookingService.getByBooker(3L, "ALL", + null, null); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + Page page = new PageImpl<>(bookingList); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerOrderByStartDesc(any(), any())) + .thenReturn(page); + + List bookings = bookingService.getByBooker(3L, "ALL", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerCURRENTTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStartBeforeAndEndAfterOrderByStartDesc(any(), any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByBooker(3L, "CURRENT", + null, null); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerCURRENTWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + Page page = new PageImpl<>(bookingList); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStartBeforeAndEndAfterOrderByStartDesc(any(), any(), + any(), any())) + .thenReturn(page); + + Collection bookings = bookingService.getByBooker(3L, "CURRENT", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerPASTTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc(any(), any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByBooker(3L, "PAST", + null, null); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerPASTWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + Page page = new PageImpl<>(bookingList); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc(any(), any(), + any(), any())) + .thenReturn(page); + + Collection bookings = bookingService.getByBooker(3L, "PAST", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerFUTURETest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStartAfterOrderByStartDesc(any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByBooker(3L, "FUTURE", + null, null); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerFUTUREWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + Page page = new PageImpl<>(bookingList); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStartAfterOrderByStartDesc(any(), any(), any())) + .thenReturn(page); + + Collection bookings = bookingService.getByBooker(3L, "FUTURE", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerWAITINGTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStatusOrderByStartDesc(any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByBooker(3L, "WAITING", + null, null); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerWAITINGWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + Page page = new PageImpl<>(bookingList); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStatusOrderByStartDesc(any(), any(), any())) + .thenReturn(page); + + Collection bookings = bookingService.getByBooker(3L, "WAITING", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerREJECTEDTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStatusOrderByStartDesc(any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByBooker(3L, "REJECTED", + null, null); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerRejectedWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2021-11-24T18:08:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + Page page = new PageImpl<>(bookingList); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByBookerAndStatusOrderByStartDesc(any(), any(), any())) + .thenReturn(page); + + Collection bookings = bookingService.getByBooker(3L, "REJECTED", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByBookerUnknownStatePageableTest() { + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final StatusBadRequestException exception = Assertions.assertThrows( + StatusBadRequestException.class, + () -> bookingService.getByBooker(3L, "RED", 0, 1)); + + Assertions.assertEquals("Unknown state: UNSUPPORTED_STATUS", exception.getMessage()); + + } + + @Test + void getBookingByBookerUnknownStateTest() { + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.getByBooker(3L, "Rjj", + null, null)); + + Assertions.assertEquals("No rights", exception.getMessage()); + + } + + @Test + void getBookingByBookerNotFoundUserTest() { + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.getByBooker(3L, null, 0, 1)); + + Assertions.assertEquals("No rights", exception.getMessage()); + + } + + @Test + void getBookingByBookerSizeOrPageLessZeroTest() { + addUser(); + addItem(); + addBooking(); + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final IllegalArgumentException exception = Assertions.assertThrows( + IllegalArgumentException.class, + () -> bookingService.getByBooker(3L, null, -1, 1)); + + Assertions.assertEquals("Page index must not be less than zero", + exception.getMessage()); + + } + + @Test + void getBookingByBookerSizeEqualZeroTest() { + addUser(); + addItem(); + addBooking(); + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> bookingService.getByBooker(3L, null, 0, 0)); + + Assertions.assertEquals("/ by zero", exception.getMessage()); + + } + + @Test + void getBookingByOwnerNotFoundUserTest() { + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> bookingService.getByOwner(1L, null, 0, 1)); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void getBookingByOwnerSizeOrPageLessZeroTest() { + addUser(); + addItem(); + addBooking(); + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final IllegalArgumentException exception = Assertions.assertThrows( + IllegalArgumentException.class, + () -> bookingService.getByOwner(1L, null, -1, 1)); + + Assertions.assertEquals("Page index must not be less than zero", + exception.getMessage()); + + } + + @Test + void getBookingByOwnerSizeEqualZeroTest() { + addUser(); + addItem(); + addBooking(); + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> bookingService.getByOwner(1L, null, 0, 0)); + + Assertions.assertEquals("/ by zero", exception.getMessage()); + + } + + @Test + void getBookingByOwnerALLTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAll(1L)) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByOwner(1L, "ALL", + null, null); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByOwnerALLWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAll(any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByOwner(1L, "ALL", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + + @Test + void getBookingByOwnerTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAll(1L)) + .thenReturn(bookingList); + + List bookings = bookingService.getByOwner(1L, "ALL", + null, null); + Assertions.assertEquals(bookingList.get(0).getId(), bookings.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings.size()); + + } + + @Test + void getBookingByOwnerWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAll(any(), any())) + .thenReturn(bookingList); + + List bookings = bookingService.getByOwner(1L, "ALL", + 0, 1); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings.size()); + + } + + @Test + // @MockitoSettings(strictness = Strictness.LENIENT) + void getBookingByOwnerCURRENTTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAndCurrent(anyLong(), any(LocalDateTime.class))) + .thenReturn(bookingList); + + List bookings = bookingService.getByOwner(1L, "CURRENT", + null, null); + + log.info(String.valueOf(bookingList.size())); + log.info(bookings.toString()); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings.size()); + + } + + @Test + void getBookingByOwnerCURRENTWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAndCurrent(any(), + any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByOwner(1L, "CURRENT", 0, + 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + + @Test + void getBookingByOwnerPASTTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAndPast(anyLong(), any(LocalDateTime.class))) + .thenReturn(bookingList); + + List bookings = bookingService.getByOwner(1L, "PAST", null, null); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings.size()); + + } + + @Test + void getBookingByOwnerPASTWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAndPast(any(), any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByOwner(1L, "PAST", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByOwnerFUTURETest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByUserAndFuture(anyLong(), any(LocalDateTime.class))) + .thenReturn(bookingList); + + List bookings = bookingService.getByOwner(1L, "FUTURE", + null, null); + Assertions.assertEquals(bookingList.get(0).getId(), bookings.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings.size()); + + } + + @Test + void getBookingByOwnerFUTUREWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByUserAndFuture(any(), any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByOwner(1L, "FUTURE", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByOwnerWAITINGTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAndByStatus(1L, Status.WAITING)) + .thenReturn(bookingList); + + List bookings = bookingService.getByOwner(1L, "WAITING", + null, null); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings.size()); + + } + + @Test + void getBookingByOwnerWAITINGWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAndByStatus(any(), any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByOwner(1L, "WAITING", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByOwnerREJECTEDTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAndByStatus(1L, Status.REJECTED)) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByOwner(1L, "REJECTED", + null, null); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByOwnerRejectedWithPageableTest() { + addUser(); + addItem(); + addBooking(); + List bookingList = new ArrayList<>(); + bookingList.add(booking); + booking.setId(2L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + bookingList.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + Mockito + .when(bookingRepository.findByOwnerAndByStatus(any(), any(), any())) + .thenReturn(bookingList); + + Collection bookings = bookingService.getByOwner(1L, "REJECTED", 0, 1); + List bookings1 = List.copyOf(bookings); + + Assertions.assertEquals(bookingList.get(0).getId(), bookings1.get(0).getId()); + Assertions.assertEquals(bookingList.size(), bookings1.size()); + + } + + @Test + void getBookingByOwnerUnknownStatePageableTest() { + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final StatusBadRequestException exception = Assertions.assertThrows( + StatusBadRequestException.class, + () -> bookingService.getByOwner(1L, "RED", 0, 1)); + + Assertions.assertEquals("Unknown state: UNSUPPORTED_STATUS", exception.getMessage()); + + } + + @Test + void getBookingByOwnerUnknownStateTest() { + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(user)); + + final StatusBadRequestException exception = Assertions.assertThrows( + StatusBadRequestException.class, + () -> bookingService.getByOwner(1L, "Rjj", + null, null)); + + Assertions.assertEquals("Unknown state: UNSUPPORTED_STATUS", exception.getMessage()); + + } + + private void addItem() { + addUser(); + item.setId(1L); + item.setName("Sword"); + item.setOwner(user); + item.setAvailable(true); + item.setDescription("For fight"); + } + + private void addUser() { + user.setId(1L); + user.setName("Aelin"); + user.setEmail("aelin@whitethorn.com"); + } + + private void addRequest() { + User requester = new User(); + requester.setId(2L); + requester.setName("Rowan"); + requester.setEmail("rowan@whitethorn.com"); + request.setId(1L); + request.setRequester(requester); + request.setDescription("waiting for fight"); + request.setCreated(LocalDateTime.now()); + } + + private void addBooking() { + User booker = new User(); + booker.setId(3L); + booker.setName("Dorian"); + booker.setEmail("dorian@havilliard.com"); + booking.setId(1L); + booking.setItem(item); + booking.setStatus(Status.WAITING); + String date = "2024-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setStart(localdatetime); + date = "2025-10-19T23:50:50"; + localdatetime = LocalDateTime.parse(date); + booking.setEnd(localdatetime); + booking.setBooker(booker); + } +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/item/CommentRepositoryTest.java b/src/test/java/ru/practicum/shareit/item/CommentRepositoryTest.java new file mode 100644 index 000000000..9da9754bb --- /dev/null +++ b/src/test/java/ru/practicum/shareit/item/CommentRepositoryTest.java @@ -0,0 +1,66 @@ +package ru.practicum.shareit.item; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +class CommentRepositoryTest { + private final Comment comment = new Comment(); + private final User user = new User(); + private final Item item = new Item(); + @Autowired + private TestEntityManager em; + @Autowired + private CommentRepository commentRepository; + + @Test + public void findByItemJpaTest() { + addComment(); + Comment commentPersist = em.persist(comment); + List comment2 = commentRepository.findAllByItem(item); + addUser(); + assertThat(commentPersist).isEqualTo(comment2.get(1)); + assertThat(commentPersist.getId()).isEqualTo(comment2.get(1).getId()); + + } + + private void addComment() { + addUser(); + addItem(); + comment.setAuthor(user); + comment.setText("I am waiting for fights"); + comment.setItem(item); + comment.setCreated(LocalDateTime.now()); + } + + private void addItem() { + User user1 = new User(); + user1.setId(2L); + user1.setName("Dorian"); + user1.setEmail("dorian@havilliard.com"); + item.setId(1L); + item.setName("Sword"); + item.setOwner(user1); + item.setAvailable(true); + item.setDescription("For fights"); + } + + private void addUser() { + user.setId(1L); + user.setName("Rowan"); + user.setEmail("rowan@whitethorn.com"); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java b/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java new file mode 100644 index 000000000..0d8ee551b --- /dev/null +++ b/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java @@ -0,0 +1,311 @@ +package ru.practicum.shareit.item; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import ru.practicum.shareit.booking.dto.BookingDTOForItem; +import ru.practicum.shareit.exception.BadRequestException; +import ru.practicum.shareit.item.dto.CommentDTO; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.item.dto.ItemDTOWithBookings; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.service.ItemServiceImpl; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@WebMvcTest(controllers = ItemController.class) +class ItemControllerTest { + + private final ItemDTO itemDto = new ItemDTO(); + private final Item item = new Item(); + private final User user = new User(); + private final Comment comment = new Comment(); + private final ItemDTOWithBookings itemDtoWithBooking = new ItemDTOWithBookings(); + private final BookingDTOForItem booking = new BookingDTOForItem(); + @Autowired + ObjectMapper mapper; + @MockBean + ItemServiceImpl itemService; + @Autowired + private MockMvc mvc; + + @Test + void addItemControllerTest() throws Exception { + addItemDto(); + + when(itemService.add(Mockito.anyLong(), any())) + .thenReturn(itemDto); + + mvc.perform(post("/items") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(itemDto.getId()), Long.class)) + .andExpect(jsonPath("$.name", is(itemDto.getName()))) + .andExpect(jsonPath("$.owner.id", is((int) itemDto.getOwner().getId()))) + .andExpect(jsonPath("$.owner.name", is(itemDto.getOwner().getName()))) + .andExpect(jsonPath("$.owner.email", is(itemDto.getOwner().getEmail()))) + .andExpect(jsonPath("$.description", is(itemDto.getDescription()))) + .andExpect(jsonPath("$.available", is(itemDto.getAvailable()))); + } + + @Test + void changeItemControllerTest() throws Exception { + addItemDto(); + + when(itemService.update(Mockito.anyLong(), Mockito.anyLong(), any())) + .thenReturn(itemDto); + + mvc.perform(patch("/items/1/") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(itemDto.getId()), Long.class)) + .andExpect(jsonPath("$.name", is(itemDto.getName()))) + .andExpect(jsonPath("$.owner.id", is((int) itemDto.getOwner().getId()))) + .andExpect(jsonPath("$.owner.name", is(itemDto.getOwner().getName()))) + .andExpect(jsonPath("$.owner.email", is(itemDto.getOwner().getEmail()))) + .andExpect(jsonPath("$.description", is(itemDto.getDescription()))) + .andExpect(jsonPath("$.available", is(itemDto.getAvailable()))); + } + + @Test + void getItemControllerTest() throws Exception { + addItemDtoWithBooking(); + + when(itemService.get(Mockito.anyLong(), Mockito.anyLong())) + .thenReturn(itemDtoWithBooking); + + mvc.perform(get("/items/1/") + .header("X-Sharer-User-Id", 1L) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(itemDtoWithBooking.getId()), Long.class)) + .andExpect(jsonPath("$.name", is(itemDtoWithBooking.getName()))) + .andExpect(jsonPath("$.owner.id", is((int) itemDtoWithBooking.getOwner().getId()))) + .andExpect(jsonPath("$.owner.name", is(itemDtoWithBooking.getOwner().getName()))) + .andExpect(jsonPath("$.owner.email", is(itemDtoWithBooking.getOwner().getEmail()))) + .andExpect(jsonPath("$.lastBooking.id", is((int) itemDtoWithBooking.getLastBooking().getId()))) + .andExpect(jsonPath("$.lastBooking.bookerId", is(itemDtoWithBooking.getLastBooking() + .getBookerId().intValue()))) + .andExpect(jsonPath("$.lastBooking.dateTime", is(itemDtoWithBooking.getLastBooking() + .getDateTime().toString()))) + .andExpect(jsonPath("$.nextBooking.id", is((int) itemDtoWithBooking.getNextBooking().getId()))) + .andExpect(jsonPath("$.nextBooking.bookerId", is(itemDtoWithBooking.getNextBooking() + .getBookerId().intValue()))) + .andExpect(jsonPath("$.nextBooking.dateTime", is(itemDtoWithBooking.getNextBooking() + .getDateTime().toString()))) + .andExpect(jsonPath("$.description", is(itemDtoWithBooking.getDescription()))) + .andExpect(jsonPath("$.available", is(itemDtoWithBooking.getAvailable()))); + } + + @Test + void getAllOwnItemsControllerTest() throws Exception { + addItemDtoWithBooking(); + List items = new ArrayList<>(); + items.add(itemDtoWithBooking); + + when(itemService.getAllByOwner(Mockito.anyLong(), any(), any())) + .thenReturn(items); + + mvc.perform(get("/items") + .header("X-Sharer-User-Id", 1L) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].id", is(itemDtoWithBooking.getId()), Long.class)) + .andExpect(jsonPath("$[0].name", is(itemDtoWithBooking.getName()))) + .andExpect(jsonPath("$[0].description", is(itemDtoWithBooking.getDescription()))) + .andExpect(jsonPath("$[0].owner.id", is((int) itemDtoWithBooking.getOwner().getId()))) + .andExpect(jsonPath("$[0].owner.name", is(itemDtoWithBooking.getOwner().getName()))) + .andExpect(jsonPath("$[0].owner.email", is(itemDtoWithBooking.getOwner().getEmail()))) + .andExpect(jsonPath("$[0].lastBooking.id", is((int) itemDtoWithBooking.getLastBooking() + .getId()))) + .andExpect(jsonPath("$[0].lastBooking.bookerId", is(itemDtoWithBooking.getLastBooking() + .getBookerId().intValue()))) + .andExpect(jsonPath("$[0].lastBooking.dateTime", is(itemDtoWithBooking.getLastBooking() + .getDateTime().toString()))) + .andExpect(jsonPath("$[0].nextBooking.id", is((int) itemDtoWithBooking.getNextBooking().getId()))) + .andExpect(jsonPath("$[0].nextBooking.bookerId", is(itemDtoWithBooking.getNextBooking() + .getBookerId().intValue()))) + .andExpect(jsonPath("$[0].nextBooking.dateTime", is(itemDtoWithBooking.getNextBooking() + .getDateTime().toString()))) + .andExpect(jsonPath("$[0].available", is(itemDtoWithBooking.getAvailable()))); + + } + + @Test + void getItemsForRentControllerTest() throws Exception { + addItemDto(); + List items = new ArrayList<>(); + items.add(itemDto); + when(itemService.getForRent(Mockito.anyString(), any(), any())) + .thenReturn(items); + + mvc.perform(get("/items/search?text=F") + .header("X-Sharer-User-Id", 1L) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].name", is(itemDto.getName()))) + .andExpect(jsonPath("$[0].owner.id", is((int) itemDto.getOwner().getId()))) + .andExpect(jsonPath("$[0].owner.name", is(itemDto.getOwner().getName()))) + .andExpect(jsonPath("$[0].owner.email", is(itemDto.getOwner().getEmail()))) + .andExpect(jsonPath("$[0].description", is(itemDto.getDescription()))) + .andExpect(jsonPath("$[0].available", is(itemDto.getAvailable()))); + } + + @Test + void addCommentControllerTest() throws Exception { + addItemDto(); + addComment(); + CommentDTO item = addItemDtoWithComment(); + when(itemService.addComment(Mockito.anyLong(), Mockito.anyLong(), any(CommentDTO.class))) + .thenReturn(item); + + mvc.perform(post("/items/1/comment") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(item.getId()), Long.class)) + .andExpect(jsonPath("$.text", is(item.getText()))) + .andExpect(jsonPath("$.itemName", is(item.getItemName()))) + .andExpect(jsonPath("$.created", is(item.getCreated().toString()))) + .andExpect(jsonPath("$.authorName", is(item.getAuthorName()))); + + } + + @Test + void addItemWithException() throws Exception { + when(itemService.add(1L, itemDto)) + .thenThrow(BadRequestException.class); + + mvc.perform(post("/items") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(status().is(400)); + } + + @Test + void updateItemWithException() throws Exception { + when(itemService.update(5L, 5L, new ItemDTO())) + .thenThrow(AssertionError.class); + + mvc.perform(patch("/items/10/") + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(status().is(500)); + } + + private void addItemDto() { + addUser(); + itemDto.setId(1L); + itemDto.setName("Sword"); + itemDto.setOwner(UserMapper.toUserToItemDto(user)); + itemDto.setAvailable(true); + itemDto.setDescription("For fights"); + } + + private void addItemDtoWithBooking() { + addBooking(); + addUser(); + itemDtoWithBooking.setId(2L); + itemDtoWithBooking.setName("Sword"); + itemDtoWithBooking.setLastBooking(booking); + booking.setId(2L); + booking.setBookerId(4L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setDateTime(localdatetime); + booking.setBookerId(4L); + itemDtoWithBooking.setNextBooking(booking); + itemDtoWithBooking.setOwner(UserMapper.toUserToItemWithBookingsDto(user)); + itemDtoWithBooking.setAvailable(true); + itemDtoWithBooking.setDescription("For fights"); + } + + private void addUser() { + user.setId(1L); + user.setName("Aelin"); + user.setEmail("aelin@whitethorn.com"); + } + + private void addBooking() { + User booker = new User(); + booker.setId(3L); + booker.setName("Dorian"); + booker.setEmail("dorian@havilliard.com"); + booking.setId(1L); + booking.setBookerId(3L); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + booking.setDateTime(localdatetime); + User booker2 = new User(); + booker2.setId(4L); + booker2.setName("Manon"); + booker2.setEmail("manon@blackbeak.com"); + + } + + private void addComment() { + User booker = new User(); + booker.setId(3L); + booker.setName("Dorian"); + booker.setEmail("dorian@havilliard.com"); + comment.setId(1L); + comment.setAuthor(booker); + comment.setItem(item); + comment.setText("amazing sword"); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + comment.setCreated(localdatetime); + } + + private CommentDTO addItemDtoWithComment() { + CommentDTO dtoWithComment = new CommentDTO(); + dtoWithComment.setId(itemDto.getId()); + dtoWithComment.setText(comment.getText()); + dtoWithComment.setItemName(itemDto.getName()); + dtoWithComment.setCreated(comment.getCreated()); + dtoWithComment.setAuthorName(comment.getAuthor().getName()); + return dtoWithComment; + } +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/item/ItemRepositoryTest.java b/src/test/java/ru/practicum/shareit/item/ItemRepositoryTest.java new file mode 100644 index 000000000..47adb168d --- /dev/null +++ b/src/test/java/ru/practicum/shareit/item/ItemRepositoryTest.java @@ -0,0 +1,96 @@ +package ru.practicum.shareit.item; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@Slf4j +class ItemRepositoryTest { + + private final Item item = new Item(); + private final User user = new User(); + private final ItemRequest request = new ItemRequest(); + @Autowired + private TestEntityManager em; + @Autowired + private ItemRepository itemRepository; + + @Test + void findItemByRequestJpaTest() { + addItem(); + addRequest(); + item.setRequestId(request); + Item itemPersist = em.persist(item); + List items = itemRepository.findByRequest(request.getId()); + assertThat(itemPersist).isEqualTo(items.get(1)); + assertThat(itemPersist.getId()).isEqualTo(items.get(1).getId()); + } + + @Test + void findByOwnerJpaTest() { + addItem(); + Item itemPersist = em.persist(item); + List items = itemRepository.findByOwner(user); + assertThat(itemPersist).isEqualTo(items.get(1)); + assertThat(itemPersist.getId()).isEqualTo(items.get(1).getId()); + } + + @Test + void findItemsByNameOrDescriptionJpaTest() { + addItem(); + Item itemPersist = em.persist(item); + List items = itemRepository.findItemsByNameOrDescription("S"); + log.info(items.toString()); + assertThat(itemPersist).isEqualTo(items.get(4)); + assertThat(itemPersist.getId()).isEqualTo(items.get(4).getId()); + } + + @Test + void findByRequestIdJpaTest() { + addItem(); + addRequest(); + item.setRequestId(request); + Item itemPersist = em.persist(item); + List items = itemRepository.findByRequest(request.getId()); + assertThat(itemPersist).isEqualTo(items.get(1)); + assertThat(itemPersist.getId()).isEqualTo(items.get(1).getId()); + } + + private void addItem() { + addUser(); + item.setName("Sword"); + item.setOwner(user); + item.setAvailable(true); + item.setDescription("For fights"); + } + + private void addUser() { + user.setId(1L); + user.setName("Aelin"); + user.setEmail("aelin@whitethorn.com"); + } + + private void addRequest() { + User requester = new User(); + requester.setId(3L); + requester.setName("Dorin"); + requester.setEmail("dorin@havilliard.com"); + request.setId(1L); + request.setRequester(requester); + request.setDescription("waiting for fight"); + request.setCreated(LocalDateTime.now()); + } +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java b/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java new file mode 100644 index 000000000..08be4403f --- /dev/null +++ b/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java @@ -0,0 +1,48 @@ +package ru.practicum.shareit.item.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.model.User; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class ItemDtoTest { + private final User user = new User(); + @Autowired + private JacksonTester json; + + @Test + void testItemDto() throws Exception { + addUser(); + ItemDTO itemDto = new ItemDTO(); + itemDto.setId(1L); + itemDto.setName("Sword"); + itemDto.setAvailable(true); + itemDto.setDescription("To fight"); + itemDto.setOwner(UserMapper.toUserToItemDto(user)); + itemDto.setRequestId(1L); + + JsonContent result = json.write(itemDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Sword"); + assertThat(result).extractingJsonPathBooleanValue("$.available").isEqualTo(true); + assertThat(result).extractingJsonPathNumberValue("$.owner.id").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.owner.name").isEqualTo("Aelin"); + assertThat(result).extractingJsonPathStringValue("$.owner.email") + .isEqualTo("aelin@whitethorn.com"); + assertThat(result).extractingJsonPathStringValue("$.description").isEqualTo("To fight"); + assertThat(result).extractingJsonPathNumberValue("$.requestId").isEqualTo(1); + } + + private void addUser() { + user.setId(1L); + user.setName("Aelin"); + user.setEmail("aelin@whitethorn.com"); + } +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingTest.java b/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingTest.java new file mode 100644 index 000000000..285a999c9 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingTest.java @@ -0,0 +1,89 @@ +package ru.practicum.shareit.item.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; +import ru.practicum.shareit.booking.dto.BookingDTOForItem; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.model.User; + +import java.io.IOException; +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class ItemDtoWithBookingTest { + + private final User user = new User(); + private final BookingDTOForItem last = new BookingDTOForItem(); + private final BookingDTOForItem next = new BookingDTOForItem(); + @Autowired + private JacksonTester json; + + @Test + void testItemDtoWithBooking() throws IOException { + addUser(); + addLast(); + addNext(); + ItemDTOWithBookings itemDtoWithBooking = new ItemDTOWithBookings(); + itemDtoWithBooking.setId(1); + itemDtoWithBooking.setName("Sword"); + itemDtoWithBooking.setDescription("To fight"); + itemDtoWithBooking.setOwner(UserMapper.toUserToItemWithBookingsDto(user)); + itemDtoWithBooking.setRequest(1L); + itemDtoWithBooking.setLastBooking(last); + itemDtoWithBooking.setNextBooking(next); + itemDtoWithBooking.setAvailable(true); + + JsonContent result = json.write(itemDtoWithBooking); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Sword"); + assertThat(result).extractingJsonPathBooleanValue("$.available").isEqualTo(true); + assertThat(result).extractingJsonPathNumberValue("$.owner.id").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.owner.name").isEqualTo("Aelin"); + assertThat(result).extractingJsonPathStringValue("$.owner.email") + .isEqualTo("aelin@whitethorn.com"); + assertThat(result).extractingJsonPathStringValue("$.description").isEqualTo("To fight"); + assertThat(result).extractingJsonPathValue("$.lastBooking.dateTime") + .isEqualTo("2017-10-19T23:50:50"); + assertThat(result).extractingJsonPathValue("$.nextBooking.dateTime") + .isEqualTo("2017-10-19T23:50:50"); + assertThat(result).extractingJsonPathNumberValue("$.request").isEqualTo(1); + + } + + private void addUser() { + user.setId(1L); + user.setName("Aelin"); + user.setEmail("aelin@whitethorn.com"); + } + + private void addLast() { + User userForLast = new User(); + userForLast.setId(2L); + userForLast.setName("Rowan"); + userForLast.setEmail("rowan@whitethorn.com"); + last.setId(1); + last.setBookerId(userForLast.getId()); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + last.setDateTime(localdatetime); + } + + private void addNext() { + User userForNext = new User(); + userForNext.setId(3L); + userForNext.setName("Rowan"); + userForNext.setEmail("rowan@whitethorn.com"); + next.setId(2); + next.setBookerId(userForNext.getId()); + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + next.setDateTime(localdatetime); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithCommentTest.java b/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithCommentTest.java new file mode 100644 index 000000000..cd800b542 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithCommentTest.java @@ -0,0 +1,39 @@ +package ru.practicum.shareit.item.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class ItemDtoWithCommentTest { + + @Autowired + private JacksonTester json; + + @Test + void testItemDtoWithComment() throws Exception { + String date = "2017-10-19T23:50:50"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + CommentDTO itemDto = new CommentDTO(); + itemDto.setId(1L); + itemDto.setItemName("Sword"); + itemDto.setText("Waiting for fight"); + itemDto.setCreated(localdatetime); + itemDto.setAuthorName("Rowan"); + + JsonContent result = json.write(itemDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.itemName").isEqualTo("Sword"); + assertThat(result).extractingJsonPathStringValue("$.text").isEqualTo("Waiting for fight"); + assertThat(result).extractingJsonPathStringValue("$.authorName").isEqualTo("Rowan"); + assertThat(result).extractingJsonPathValue("$.created").isEqualTo("2017-10-19T23:50:50"); + + } +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/item/service/ItemServiceTest.java b/src/test/java/ru/practicum/shareit/item/service/ItemServiceTest.java new file mode 100644 index 000000000..f7fcf9854 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/item/service/ItemServiceTest.java @@ -0,0 +1,637 @@ +package ru.practicum.shareit.item.service; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.booking.BookingRepository; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.model.Status; +import ru.practicum.shareit.exception.BadRequestException; +import ru.practicum.shareit.exception.ForbiddenException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.item.CommentRepository; +import ru.practicum.shareit.item.ItemRepository; +import ru.practicum.shareit.item.dto.CommentDTO; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.item.dto.ItemDTOWithBookings; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.RequestRepository; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.UserRepository; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@ExtendWith(MockitoExtension.class) +@Slf4j +class ItemServiceTest { + + @InjectMocks + ItemServiceImpl itemService; + + @Mock + ItemRepository itemRepository; + + @Mock + UserRepository userRepository; + + @Mock + RequestRepository requestRepository; + + @Mock + CommentRepository commentRepository; + + @Mock + BookingRepository bookingRepository; + + Item item = new Item(); + User userOwner = new User(); + User requester = new User(); + ItemRequest request = new ItemRequest(); + Booking booking = new Booking(); + Comment comment = new Comment(); + + + @Test + void addItemTest() { + addItem(); + addRequest(); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(userOwner)); + + Mockito + .when(itemRepository.save(any())) + .thenReturn(item); + + Optional itemDto = Optional.ofNullable(itemService.add(userOwner.getId(), + ItemMapper.toItemDto(item))); + + assertThat(itemDto) + .isPresent() + .hasValueSatisfying(addItemTest -> { + assertThat(addItemTest).hasFieldOrPropertyWithValue("id", item.getId()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("name", item.getName()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("available", item.getAvailable()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("description", + item.getDescription()); + } + ); + } + + @Test + void addItemWithRequestTest() { + addItem(); + addRequest(); + item.setRequestId(request); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(userOwner)); + + Mockito + .when(itemRepository.save(any())) + .thenReturn(item); + + Optional itemDto = Optional.ofNullable(itemService.add(userOwner.getId(), + ItemMapper.toItemDto(item))); + + assertThat(itemDto) + .isPresent() + .hasValueSatisfying(addItemTest -> { + assertThat(addItemTest).hasFieldOrPropertyWithValue("id", item.getId()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("name", item.getName()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("available", item.getAvailable()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("requestId", + item.getRequestId().getId()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("description", + item.getDescription()); + } + ); + } + + @Test + void addItemUserNotFoundTest() { + addItem(); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> itemService.add(3L, ItemMapper.toItemDto(item))); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void changeItemTest() { + addItem(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Optional itemDto = Optional.ofNullable(itemService.update(userOwner.getId(), item.getId(), + ItemMapper.toItemDto(item))); + + assertThat(itemDto) + .isPresent() + .hasValueSatisfying(addItemTest -> { + assertThat(addItemTest).hasFieldOrPropertyWithValue("id", item.getId()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("name", item.getName()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("available", item.getAvailable()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("description", + item.getDescription()); + } + ); + } + + @Test + void changeItemNotFoundTest() { + addItem(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> itemService.update(1L, 3L, ItemMapper.toItemDto(item))); + + Assertions.assertEquals("Item not found", exception.getMessage()); + } + + @Test + void changeItemForbiddenExceptionTest() { + addItem(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + final ForbiddenException exception = Assertions.assertThrows( + ForbiddenException.class, + () -> itemService.update(5L, 1L, ItemMapper.toItemDto(item))); + + Assertions.assertEquals("No rights", exception.getMessage()); + } + + @Test + void getItemTest() { + addItem(); + List comments = new ArrayList<>(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Mockito + .when(commentRepository.findAllByItem(any())) + .thenReturn(comments); + + Optional itemDto = Optional.ofNullable(itemService.get(userOwner.getId(), item.getId())); + + assertThat(itemDto) + .isPresent() + .hasValueSatisfying(addItemTest -> { + assertThat(addItemTest).hasFieldOrPropertyWithValue("id", item.getId()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("name", item.getName()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("available", item.getAvailable()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("description", + item.getDescription()); + } + ); + } + + @Test + void getItemWithBookingTest() { + addItem(); + addBooking(); + List comments = new ArrayList<>(); + List bookings = new ArrayList<>(); + bookings.add(booking); + booking.setId(2L); + bookings.add(booking); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(item)); + + Mockito + .when(commentRepository.findAllByItem(any())) + .thenReturn(comments); + + Optional itemDto = Optional.ofNullable(itemService.get(userOwner.getId(), item.getId())); + + assertThat(itemDto) + .isPresent() + .hasValueSatisfying(addItemTest -> { + assertThat(addItemTest).hasFieldOrPropertyWithValue("id", item.getId()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("name", item.getName()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("available", item.getAvailable()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("description", + item.getDescription()); + } + ); + } + + @Test + void getNotFoundTest() { + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> itemService.get(1L, 5L)); + + Assertions.assertEquals("Item not found", exception.getMessage()); + + } + + @Test + void getAllOwnItemsTest() { + addItem(); + addBooking(); + List bookings = new ArrayList<>(); + List items = new ArrayList<>(); + items.add(item); + bookings.add(booking); + booking.setId(2L); + bookings.add(booking); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(userOwner)); + + Mockito + .when(itemRepository.findByOwner(any())) + .thenReturn(items); + + List getItems = itemService.getAllByOwner(1L, null, null); + + Assertions.assertEquals(getItems.get(0).getId(), items.get(0).getId()); + } + + @Test + void getAllOwnItemsNotFoundUserTest() { + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> itemService.getAllByOwner(4L, null, null)); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void getAllOwnItemsFromOrSizeLessThanZeroTest() { + addItem(); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(userOwner)); + + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> itemService.getAllByOwner(1L, -1, 0)); + + Assertions.assertEquals("/ by zero", + exception.getMessage()); + } + + @Test + void getAllOwnItemsSizeEqualToZeroTest() { + addItem(); + + List items = new ArrayList<>(); + items.add(item); + + + Mockito.when(userRepository.findById(any())) + .thenReturn(Optional.ofNullable((userOwner))); + + log.info(userOwner.toString()); + log.info(String.valueOf(userRepository.getReferenceById(1L))); + log.info(item.getOwner().toString()); + + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> itemService.getAllByOwner(1L, 1, 0)); + + Assertions.assertEquals("/ by zero", exception.getMessage()); + } + + @Test + void getAllOwnItemsWithPageTest() { + addItem(); + addBooking(); + List bookings = new ArrayList<>(); + List items = new ArrayList<>(); + items.add(item); + bookings.add(booking); + booking.setId(2L); + bookings.add(booking); + Page page = new PageImpl<>(items); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(userOwner)); + + Mockito + .when(itemRepository.findByOwner(any(), any())) + .thenReturn(page); + + List getItems = itemService.getAllByOwner(1L, 0, 1); + + Assertions.assertEquals(getItems.get(0).getId(), items.get(0).getId()); + } + + + @Test + void getItemsForRentTest() { + addItem(); + List items = new ArrayList<>(); + items.add(item); + + Mockito + .when(itemRepository.findItemsByNameOrDescription(Mockito.anyString())) + .thenReturn(items); + + List getItems = itemService.getForRent("Sword", null, null); + + Assertions.assertEquals(getItems.get(0).getId(), items.get(0).getId()); + } + + @Test + void getItemsForRentEqualToZeroTest() { + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> itemService.getForRent("S", 0, 0)); + + Assertions.assertEquals("/ by zero", exception.getMessage()); + + } + + @Test + void getItemsForRentFromOrSizeLessThanZeroTest() { + final ArithmeticException exception = Assertions.assertThrows( + ArithmeticException.class, + () -> itemService.getForRent("S", -1, 0)); + + Assertions.assertEquals("/ by zero", + exception.getMessage()); + + } + + @Test + void getItemsForRentWithPageTest() { + addItem(); + List items = new ArrayList<>(); + items.add(item); + Page page = new PageImpl<>(items); + + Mockito + .when(itemRepository.findItemsByNameOrDescription(Mockito.anyString(), any())) + .thenReturn(page); + + List getItems = itemService.getForRent("Sword", 0, 1); + + Assertions.assertEquals(getItems.get(0).getId(), items.get(0).getId()); + } + + @Test + void getItemsForRentNewArrayTest() { + List getItems = itemService.getForRent("", null, null); + + Assertions.assertEquals(getItems, new ArrayList<>()); + } + + @Test + void addCommentTest() { + addItem(); + addComment(); + addBooking(); + booking.setStart(LocalDateTime.now().minusDays(3)); + booking.setEnd(LocalDateTime.now().minusDays(2)); + List bookings = new ArrayList<>(); + bookings.add(booking); + CommentDTO dtoWithComment = addItemDtoWithComment(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(comment.getAuthor())); + + Mockito + .when(bookingRepository.findByItemAndBookerAndStartBeforeAndEndBefore(any(), any(), + any(), any())) + .thenReturn(bookings); + + Mockito + .when(commentRepository.save(any())) + .thenReturn(comment); + + Optional itemDto = Optional.ofNullable(itemService.addComment(3L, item.getId(), + dtoWithComment)); + + assertThat(itemDto) + .isPresent() + .hasValueSatisfying(addItemTest -> { + assertThat(addItemTest).hasFieldOrPropertyWithValue("id", item.getId()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("text", comment.getText()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("itemName", item.getName()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("created", comment.getCreated()); + assertThat(addItemTest).hasFieldOrPropertyWithValue("authorName", + comment.getAuthor().getName()); + } + ); + } + + @Test + void addCommentItemNotFoundTest() { + addItem(); + addComment(); + CommentDTO dtoWithComment = addItemDtoWithComment(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> itemService.addComment(2L, 2L, dtoWithComment)); + + Assertions.assertEquals("Item not found", exception.getMessage()); + } + + @Test + void addCommentUserNotFoundTest() { + addItem(); + addComment(); + CommentDTO dtoWithComment = addItemDtoWithComment(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> itemService.addComment(4L, 1L, dtoWithComment)); + + Assertions.assertEquals("User not found", exception.getMessage()); + + } + + @Test + void addCommentBookingIsEmptyTest() { + addItem(); + addComment(); + CommentDTO dtoWithComment = addItemDtoWithComment(); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(comment.getAuthor())); + + Mockito + .when(bookingRepository.findByItemAndBookerAndStartBeforeAndEndBefore(any(), any(), + any(), any())) + .thenReturn(new ArrayList<>()); + + final BadRequestException exception = Assertions.assertThrows( + BadRequestException.class, + () -> itemService.addComment(4L, 1L, dtoWithComment)); + + Assertions.assertEquals("Booking is empty", exception.getMessage()); + + + } + + @Test + void addCommentIsEmptyTest() { + addItem(); + addComment(); + addBooking(); + booking.setStart(LocalDateTime.now().minusDays(3)); + booking.setEnd(LocalDateTime.now().minusDays(2)); + List bookings = new ArrayList<>(); + bookings.add(booking); + + Mockito + .when(itemRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(item)); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(comment.getAuthor())); + + Mockito + .when(bookingRepository.findByItemAndBookerAndStartBeforeAndEndBefore(any(), any(), + any(), any())) + .thenReturn(bookings); + + final BadRequestException exception = Assertions.assertThrows( + BadRequestException.class, + () -> itemService.addComment(4L, 1L, null)); + + Assertions.assertEquals("Comment is empty", exception.getMessage()); + + + } + + + private void addItem() { + addUser(); + item.setId(1L); + item.setName("Sword"); + item.setOwner(userOwner); + item.setAvailable(true); + item.setDescription("For fight"); + } + + private void addUser() { + userOwner.setId(1L); + userOwner.setName("Aelin"); + userOwner.setEmail("aelin@whitethorn.com"); + + requester.setId(2L); + requester.setName("Rowan"); + requester.setEmail("leo@angel.com"); + } + + private void addRequest() { + request.setId(1L); + request.setRequester(requester); + request.setDescription("waiting for fight"); + request.setCreated(LocalDateTime.now()); + } + + private void addBooking() { + User booker = new User(); + booker.setId(3L); + booker.setName("Dorin"); + booker.setEmail("dorin@havilliard.com"); + booking.setId(1L); + booking.setItem(item); + booking.setStatus(Status.WAITING); + booking.setStart(LocalDateTime.now().plusDays(1)); + booking.setEnd(LocalDateTime.now().plusDays(3)); + booking.setBooker(booker); + } + + private void addComment() { + User booker = new User(); + booker.setId(3L); + booker.setName("Dorin"); + booker.setEmail("dorin@havilliard.com"); + comment.setId(1L); + comment.setAuthor(booker); + comment.setItem(item); + comment.setText("amazing sword"); + comment.setCreated(LocalDateTime.now()); + } + + private CommentDTO addItemDtoWithComment() { + CommentDTO dtoWithComment = new CommentDTO(); + dtoWithComment.setId(item.getId()); + dtoWithComment.setText(comment.getText()); + dtoWithComment.setItemName(item.getName()); + dtoWithComment.setCreated(comment.getCreated()); + dtoWithComment.setAuthorName(comment.getAuthor().getName()); + return dtoWithComment; + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java b/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java new file mode 100644 index 000000000..0826c6cfc --- /dev/null +++ b/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java @@ -0,0 +1,149 @@ +package ru.practicum.shareit.request; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.servlet.MockMvc; +import ru.practicum.shareit.item.dto.ItemDTO; +import ru.practicum.shareit.request.dto.RequestDTO; +import ru.practicum.shareit.request.dto.RequestDTOWithItems; +import ru.practicum.shareit.request.service.RequestService; +import ru.practicum.shareit.user.model.User; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.List; + +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@WebMvcTest(controllers = ItemRequestController.class) +class ItemRequestControllerTest { + + private final RequestDTO requestDto = new RequestDTO(); + private final RequestDTOWithItems requestWithItems = new RequestDTOWithItems(); + private final ItemDTO itemDto = new ItemDTO(); + private final User user = new User(); + @Autowired + ObjectMapper mapper; + @MockBean + RequestService requestService; + @Autowired + private MockMvc mvc; + + @Test + void addRequestControllerTest() throws Exception { + addRequestDto(); + + when(requestService.add(Mockito.anyLong(), any())) + .thenReturn(requestDto); + + mvc.perform(post("/requests") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(requestDto.getId()), Long.class)) + .andExpect(jsonPath("$.created", is(requestDto.getCreated().toString()))) + .andExpect(jsonPath("$.description", is(requestDto.getDescription()))); + } + + @Test + void getAllOwnRequestControllerTest() throws Exception { + addRequest(); + + when(requestService.findAllByOwner(Mockito.anyLong())) + .thenReturn(List.of(requestWithItems)); + + mvc.perform(get("/requests") + .header("X-Sharer-User-Id", 2L) + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id", is(requestWithItems.getId()), Long.class)) + .andExpect(jsonPath("$[0].created", is(requestWithItems.getCreated().toString()))) + .andExpect(jsonPath("$[0].description", is(requestWithItems.getDescription()))); + } + + @Test + void getAllRequestControllerTest() throws Exception { + addRequest(); + + when(requestService.findAll(Mockito.anyLong(), any(), any())) + .thenReturn(List.of(requestWithItems)); + + mvc.perform(get("/requests/all") + .header("X-Sharer-User-Id", 2L) + .param("from", "0") + .param("size", "1") + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id", is(requestWithItems.getId()), Long.class)) + .andExpect(jsonPath("$[0].created", is(requestWithItems.getCreated().toString()))) + .andExpect(jsonPath("$[0].description", is(requestWithItems.getDescription()))); + } + + @Test + void getRequestControllerTest() throws Exception { + addRequest(); + + when(requestService.findById(Mockito.anyLong(), Mockito.anyLong())) + .thenReturn(requestWithItems); + + mvc.perform(get("/requests/2") + .header("X-Sharer-User-Id", 1L) + .content(mapper.writeValueAsString(itemDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(requestWithItems.getId()), Long.class)) + .andExpect(jsonPath("$.created", is(requestWithItems.getCreated().toString()))) + .andExpect(jsonPath("$.description", is(requestWithItems.getDescription()))); + } + + private void addUser() { + user.setId(1L); + user.setName("Aelin"); + user.setEmail("aelin@whitethorn.com"); + } + + private void addRequestDto() { + addUser(); + requestDto.setId(1L); + requestDto.setDescription("waiting for fight"); + String date = "2022-11-23T12:30:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + requestDto.setCreated(localdatetime); + } + + private void addRequest() { + addUser(); + user.setId(1L); + user.setName("Rowan"); + requestWithItems.setId(2L); + requestWithItems.setDescription("waiting for fight"); + String date = "2022-11-24T12:30:54"; + LocalDateTime localdatetime = LocalDateTime.parse(date); + requestWithItems.setCreated(localdatetime); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/request/ItemRequestRepositoryTest.java b/src/test/java/ru/practicum/shareit/request/ItemRequestRepositoryTest.java new file mode 100644 index 000000000..e1c95c528 --- /dev/null +++ b/src/test/java/ru/practicum/shareit/request/ItemRequestRepositoryTest.java @@ -0,0 +1,73 @@ +package ru.practicum.shareit.request; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +class ItemRequestRepositoryTest { + + private final ItemRequest requestOne = new ItemRequest(); + private final ItemRequest requestTwo = new ItemRequest(); + List requestsPersist = new ArrayList<>(); + @Autowired + private TestEntityManager em; + @Autowired + private RequestRepository rRepository; + + @Test + void findByRequesterOrderByCreatedDesc() { + addRequestOne(); + em.persist(requestOne); + addRequestTwo(); + em.persist(requestTwo); + requestsPersist.add(requestTwo); + requestsPersist.add(requestOne); + List requests = rRepository.findByRequesterOrderByCreatedDesc(requestOne.getRequester()); + assertThat(requestsPersist.get(0).getId()).isEqualTo(requests.get(0).getId()); + } + + @Test + void findAllBy() { + Pageable pageable = PageRequest.of(0, 3); + Page requestsPage = rRepository.findAllBy(2L, pageable); + List requests = requestsPage.getContent(); + assertThat(requests.size()).isEqualTo(3); + assertThat(requests.get(0).getId()).isEqualTo(1); + } + + private void addRequestOne() { + User requester = new User(); + requester.setId(2L); + requester.setName("Rowan"); + requester.setEmail("rowan@whitethorn.com"); + requestOne.setRequester(requester); + requestOne.setDescription("waiting for fight"); + requestOne.setCreated(LocalDateTime.now()); + } + + private void addRequestTwo() { + User requester = new User(); + requester.setId(2L); + requester.setName("Rowan"); + requester.setEmail("rowan@whitethorn.com"); + requestTwo.setRequester(requester); + requestTwo.setDescription("waiting for fight"); + requestTwo.setCreated(LocalDateTime.now()); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/request/service/ItemRequestServiceTest.java b/src/test/java/ru/practicum/shareit/request/service/ItemRequestServiceTest.java new file mode 100644 index 000000000..0351fdd9e --- /dev/null +++ b/src/test/java/ru/practicum/shareit/request/service/ItemRequestServiceTest.java @@ -0,0 +1,307 @@ +package ru.practicum.shareit.request.service; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.item.ItemRepository; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.RequestMapper; +import ru.practicum.shareit.request.RequestRepository; +import ru.practicum.shareit.request.dto.RequestDTO; +import ru.practicum.shareit.request.dto.RequestDTOWithItems; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.UserRepository; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@ExtendWith(MockitoExtension.class) +@Slf4j +class ItemRequestServiceTest { + + @InjectMocks + RequestServiceImpl requestService; + + @Mock + ItemRepository itemRepository; + + @Mock + UserRepository userRepository; + + @Mock + RequestRepository requestRepository; + + ItemRequest request = new ItemRequest(); + User requester = new User(); + Item item = new Item(); + + @Test + void addRequestTest() { + addRequest(); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(requester)); + + Mockito + .when(requestRepository.save(any())) + .thenReturn(request); + + Optional requestDto = Optional.ofNullable(requestService.add(1L, + RequestMapper.toRequestDto(request))); + + assertThat(requestDto) + .isPresent() + .hasValueSatisfying(addRequestTest -> { + assertThat(addRequestTest).hasFieldOrPropertyWithValue("id", request.getId()); + assertThat(addRequestTest).hasFieldOrPropertyWithValue("requester.id", + request.getRequester().getId()); + assertThat(addRequestTest).hasFieldOrPropertyWithValue("description", + request.getDescription()); + assertThat(addRequestTest).hasFieldOrPropertyWithValue("created", + request.getCreated()); + } + ); + } + + @Test + void addRequestUserNotFoundTest() { + addRequest(); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> requestService.add(3L, RequestMapper.toRequestDto(request))); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void findAllOwnRequestTest() { + addRequest(); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(requester)); + + Mockito + .when(requestRepository.findByRequesterOrderByCreatedDesc(any())) + .thenReturn(List.of(request)); + + List requestDtos = requestService.findAllByOwner(1L); + + Assertions.assertEquals(request.getId(), requestDtos.get(0).getId()); + } + + @Test + void findAllOwnRequestWithItemTest() { + addRequest(); + addItem(); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.of(requester)); + + Mockito + .when(requestRepository.findByRequesterOrderByCreatedDesc(any())) + .thenReturn(List.of(request)); + + Mockito + .when(itemRepository.findByRequest(Mockito.anyLong())) + .thenReturn(List.of(item)); + + List requestDtos = requestService.findAllByOwner(1L); + + Assertions.assertEquals(request.getId(), requestDtos.get(0).getId()); + } + + @Test + void findAllOwnRequestNotFoundUserTest() { + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> requestService.findAllByOwner(5L)); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void findAllRequestWithPageableTest() { + addRequest(); + addItem(); + List items = new ArrayList<>(); + items.add(item); + List requests = new ArrayList<>(); + requests.add(request); + request.setCreated(LocalDateTime.now().minusHours(5)); + request.setId(2L); + requests.add(request); + List page = new ArrayList<>(requests); + + Mockito + .when(requestRepository.findAllByRequester_IdNot(Mockito.anyLong(), any())) + .thenReturn(page); + + List requestDtos = requestService.findAll(1L, 0, 1); + + log.info(requestDtos.toString()); + + Assertions.assertEquals(request.getId(), requestDtos.get(0).getId()); + + } + + @Test + void findAllRequestTest() { + addRequest(); + addItem(); + List items = new ArrayList<>(); + items.add(item); + List requests = new ArrayList<>(); + requests.add(request); + request.setCreated(LocalDateTime.now().minusHours(5)); + request.setId(2L); + requests.add(request); + + Mockito + .when(requestRepository.findAllByRequester_IdNot(Mockito.anyLong(), any())) + .thenReturn(requests); + + List requestDtos = requestService.findAll(1L, 0, 1); + + Assertions.assertEquals(request.getId(), requestDtos.get(0).getId()); + + } + + @Test + void findAllRequestSizeOrPageLessZeroTest() { + final IllegalArgumentException exception = Assertions.assertThrows( + IllegalArgumentException.class, + () -> requestService.findAll(1L, 1, -1)); + + Assertions.assertEquals("Page size must not be less than one", + exception.getMessage()); + + } + + @Test + void findAllRequestSizeEqualZeroTest() { + final IllegalArgumentException exception = Assertions.assertThrows( + IllegalArgumentException.class, + () -> requestService.findAll(1L, 1, 0)); + + Assertions.assertEquals("Page size must not be less than one", + exception.getMessage()); + + } + + @Test + void findRequestTest() { + addRequest(); + addItem(); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(requester)); + + Mockito + .when(requestRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(request)); + + Optional requestDto = Optional.ofNullable(requestService.findById(1L, 1L)); + + assertThat(requestDto) + .isPresent() + .hasValueSatisfying(addRequestTest -> { + assertThat(addRequestTest).hasFieldOrPropertyWithValue("id", request.getId()); + assertThat(addRequestTest).hasFieldOrPropertyWithValue("requester.id", + request.getRequester().getId()); + assertThat(addRequestTest).hasFieldOrPropertyWithValue("description", + request.getDescription()); + assertThat(addRequestTest).hasFieldOrPropertyWithValue("created", + request.getCreated()); + } + ); + + } + + @Test + void findRequestNotFoundUserTest() { + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> requestService.findById(3L, 1L)); + + Assertions.assertEquals("User not found", exception.getMessage()); + + } + + @Test + void findRequestNotFounTest() { + addUser(); + + Mockito + .when(userRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.ofNullable(requester)); + + Mockito + .when(requestRepository.findById(Mockito.anyLong())) + .thenReturn(Optional.empty()); + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> requestService.findById(3L, 1L)); + + Assertions.assertEquals("Request not found", exception.getMessage()); + + } + + private void addUser() { + requester.setId(1L); + requester.setName("Aelin"); + requester.setEmail("aelin@whitethorn.com"); + } + + private void addRequest() { + addUser(); + request.setId(1L); + request.setRequester(requester); + request.setDescription("waiting for fight"); + request.setCreated(LocalDateTime.now()); + } + + private void addItem() { + User owner = new User(); + owner.setId(2L); + owner.setName("Aelin"); + owner.setEmail("aelin@whitethorn.com"); + item.setId(1L); + item.setName("Sword"); + item.setOwner(owner); + item.setAvailable(true); + item.setDescription("For fights"); + item.setRequestId(request); + } +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/user/UserControllerTest.java b/src/test/java/ru/practicum/shareit/user/UserControllerTest.java new file mode 100644 index 000000000..f4778826d --- /dev/null +++ b/src/test/java/ru/practicum/shareit/user/UserControllerTest.java @@ -0,0 +1,156 @@ +package ru.practicum.shareit.user; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import ru.practicum.shareit.exception.BadRequestException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.user.dto.UserDTO; +import ru.practicum.shareit.user.service.UserServiceImpl; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@WebMvcTest(controllers = UserController.class) +class UserControllerTest { + + private final UserDTO userDto = new UserDTO(); + @Autowired + ObjectMapper mapper; + @MockBean + UserServiceImpl userService; + @Autowired + private MockMvc mvc; + + @Test + void createUserControllerTest() throws Exception { + addUser(); + + when(userService.create(any())) + .thenReturn(userDto); + + mvc.perform(post("/users") + .content(mapper.writeValueAsString(userDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(userDto.getId()), Long.class)) + .andExpect(jsonPath("$.name", is(userDto.getName()))) + .andExpect(jsonPath("$.email", is(userDto.getEmail()))); + } + + @Test + void updateUserControllerTest() throws Exception { + addUser(); + + when(userService.update(1L, userDto)) + .thenReturn(userDto); + + mvc.perform(patch("/users/1/") + .content(mapper.writeValueAsString(userDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(userDto.getId()), Long.class)) + .andExpect(jsonPath("$.name", is(userDto.getName()))) + .andExpect(jsonPath("$.email", is(userDto.getEmail()))); + } + + @Test + void deleteUserControllerTest() throws Exception { + addUser(); + mvc.perform(MockMvcRequestBuilders.delete("/users/1/")) + .andExpect(status().isOk()); + + } + + @Test + void getUsersControllerTest() throws Exception { + addUser(); + when(userService.getAll()) + .thenReturn(List.of(userDto)); + + mvc.perform(get("/users")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].id", is(userDto.getId()), Long.class)) + .andExpect(jsonPath("$[0].name", is(userDto.getName()))) + .andExpect(jsonPath("$[0].email", is(userDto.getEmail()))); + } + + + @Test + void getUserControllerTest() throws Exception { + addUser(); + when(userService.get(Mockito.anyLong())) + .thenReturn(userDto); + + mvc.perform(get("/users/1/")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", is(userDto.getId()), Long.class)) + .andExpect(jsonPath("$.name", is(userDto.getName()))) + .andExpect(jsonPath("$.email", is(userDto.getEmail()))); + } + + + @Test + void createUserWithException() throws Exception { + when(userService.create(any())) + .thenThrow(BadRequestException.class); + + mvc.perform(post("/users") + .content(mapper.writeValueAsString(userDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(status().is(400)); + } + + @Test + void updateUserWithException() throws Exception { + when(userService.update(1L, userDto)) + .thenThrow(NotFoundException.class); + + mvc.perform(patch("/users/1/") + .content(mapper.writeValueAsString(userDto)) + .characterEncoding(StandardCharsets.UTF_8) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(status().is(404)); + } + + @Test + void deleteUserWithException() throws Exception { + doReturn(Exception.class); + mvc.perform(MockMvcRequestBuilders.delete("/users/1/")) + .andExpect(status().is(500)); + } + + private void addUser() { + userDto.setId(1L); + userDto.setName("Aelin"); + userDto.setEmail("aelin@whitethorn.com"); + } +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java b/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java new file mode 100644 index 000000000..69c25570a --- /dev/null +++ b/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java @@ -0,0 +1,30 @@ +package ru.practicum.shareit.user.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.boot.test.json.JsonContent; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class UserDtoTest { + @Autowired + private JacksonTester json; + + @Test + void testUserDto() throws Exception { + UserDTO userDto = new UserDTO(); + userDto.setId(1L); + userDto.setName("Aelin"); + userDto.setEmail("aelin@whitethorn.com"); + + JsonContent result = json.write(userDto); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Aelin"); + assertThat(result).extractingJsonPathStringValue("$.email").isEqualTo("aelin@whitethorn.com"); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/user/service/UserServiceTest.java b/src/test/java/ru/practicum/shareit/user/service/UserServiceTest.java new file mode 100644 index 000000000..fffa0a09a --- /dev/null +++ b/src/test/java/ru/practicum/shareit/user/service/UserServiceTest.java @@ -0,0 +1,202 @@ +package ru.practicum.shareit.user.service; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.annotation.DirtiesContext; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.user.UserMapper; +import ru.practicum.shareit.user.UserRepository; +import ru.practicum.shareit.user.dto.UserDTO; +import ru.practicum.shareit.user.model.User; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@ExtendWith(MockitoExtension.class) +class UserServiceTest { + + private final User user = new User(); + private final UserDTO userDTO = new UserDTO(); + @InjectMocks + UserServiceImpl mockUserService; + @Mock + UserRepository userRepository; + + private void addUser() { + user.setName("Aelin"); + user.setId(1L); + user.setEmail("aelin@whitethorn.com"); + } + + private void addUserDTO() { + user.setName("Aelin"); + user.setId(1L); + user.setEmail("aelin@whitethorn.com"); + } + + @Test + void addUserTest() { + addUser(); + + Mockito + .when(userRepository.save(any())) + .thenReturn(user); + + Optional userDto = Optional.ofNullable(mockUserService.create(UserMapper.toUserDto(user))); + assertThat(userDto) + .isPresent() + .hasValueSatisfying(addUserTest -> { + assertThat(addUserTest).hasFieldOrPropertyWithValue("id", user.getId()); + assertThat(addUserTest).hasFieldOrPropertyWithValue("name", user.getName()); + assertThat(addUserTest).hasFieldOrPropertyWithValue("email", user.getEmail()); + } + ); + } + + @Test + void updateUserExceptionTest() { + addUserDTO(); + + Mockito + .when(userRepository.findById(2L)) + .thenThrow(new NotFoundException("User not found")); + + + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> mockUserService.update(2L, userDTO)); + + Assertions.assertEquals("User not found", exception.getMessage()); + + + } + + @Test + void updateUserEmptyTest() { + addUserDTO(); + Mockito + .when(userRepository.findById(0L)) + .thenReturn(Optional.empty()); + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> mockUserService.update(0L, userDTO)); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void updateUserTest() { + addUser(); + + Mockito + .when(userRepository.findById(1L)) + .thenReturn(Optional.of(user)); + + Optional userDto = Optional.ofNullable(mockUserService.update(1L, (UserMapper.toUserDto(user)))); + assertThat(userDto) + .isPresent() + .hasValueSatisfying(addUserTest -> { + assertThat(addUserTest).hasFieldOrPropertyWithValue("id", user.getId()); + assertThat(addUserTest).hasFieldOrPropertyWithValue("name", user.getName()); + assertThat(addUserTest).hasFieldOrPropertyWithValue("email", user.getEmail()); + } + ); + } + + @Test + void deleteUserExceptionTest() { + Mockito + .when(userRepository.findById(1L)) + .thenReturn(Optional.empty()); + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> mockUserService.delete(1L)); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void deleteUserTest() { + addUser(); + + Mockito + .when(userRepository.findById(1L)) + .thenReturn(Optional.of(user)); + mockUserService.delete(1L); + Mockito.verify(userRepository).deleteById(1L); + + } + + @Test + void getAllUsersEmptyTest() { + Mockito + .when(userRepository.findAll()) + .thenReturn(new ArrayList<>()); + List userDtoList = mockUserService.getAll(); + Assertions.assertEquals(userDtoList, new ArrayList<>()); + + + } + + @Test + void getAllUsersTest() { + addUser(); + + User user1 = new User(); + user1.setId(2L); + user1.setName("Rowan"); + user1.setEmail("rowan@whitethorn.com"); + + List users = new ArrayList<>(); + users.add(user1); + users.add(user); + + Mockito + .when(userRepository.findAll()) + .thenReturn(users); + + List getUsers = UserMapper.mapToUser(mockUserService.getAll()); + Assertions.assertEquals(getUsers, users); + } + + @Test + void getUserExceptionTest() { + Mockito + .when(userRepository.findById(1L)) + .thenReturn(Optional.empty()); + final NotFoundException exception = Assertions.assertThrows( + NotFoundException.class, + () -> mockUserService.get(1L)); + + Assertions.assertEquals("User not found", exception.getMessage()); + } + + @Test + void getUserTest() { + addUser(); + + Mockito + .when(userRepository.findById(1L)) + .thenReturn(Optional.of(user)); + + Optional userDto = Optional.ofNullable(mockUserService.get(1L)); + assertThat(userDto) + .isPresent() + .hasValueSatisfying(addUserTest -> { + assertThat(addUserTest).hasFieldOrPropertyWithValue("id", user.getId()); + assertThat(addUserTest).hasFieldOrPropertyWithValue("name", user.getName()); + assertThat(addUserTest).hasFieldOrPropertyWithValue("email", user.getEmail()); + } + ); + } +} \ No newline at end of file diff --git a/src/test/resources/data.sql b/src/test/resources/data.sql new file mode 100644 index 000000000..da354a4bb --- /dev/null +++ b/src/test/resources/data.sql @@ -0,0 +1,26 @@ +INSERT INTO USERS (NAME, EMAIL) +VALUES ('Aelin', 'aelin@whitethorn.com'), + ('Rowan', 'rowan@whitethorn.com'), + ('Dorin', 'dorian@havilliard.com'), + ('Manon', 'manon@blackbeack.com'); + +INSERT INTO REQUESTS (DESCRIPTION, REQUESTER_ID, CREATED) +VALUES ('waiting for fight', '1', '2023-02-11 19:00:01'), + ('going to survey', '2', '2023-02-11 19:00:01'), + ('just wanted to read', '3', '2023-02-11 19:00:01'), + ('Where is my crown?', '4', '2023-02-11 19:00:01'); + +INSERT INTO ITEMS (NAME, DESCRIPTION, AVAILABLE, OWNER_ID, REQUEST_ID) +VALUES ('Sword', 'For fights', true, '3', '1'), + ('Knives', 'very sharp', true, '1', '2'), + ('Old books', 'very old and maybe dangerous', true, '4', '3'), + ('Crown', 'Very shiny', true, '2', '4'); + +INSERT INTO BOOKINGS (START_DATE, END_DATE, ITEM_ID, BOOKER_ID, STATUS) +VALUES ('2022-11-11 12:32:59', '2023-02-11 19:00:01', '1', '4', 'WAITING'), + ('2022-11-11 12:32:59', '2024-11-25 12:32:59', '2', '3', 'WAITING'), + ('2024-11-11 12:32:59', '2025-11-25 12:32:59', '3', '2', 'WAITING'), + ('2023-11-11 12:32:59', '2023-02-11 19:00:01', '4', '1', 'WAITING'); + +INSERT INTO COMMENTS (TEXT, ITEM_ID, AUTHOR_ID, CREATED) +VALUES ('Amazing sword', '1', '4', '2022-11-25 12:34:59');