@@ -0,0 +1,85 @@ | |||
*.db | |||
############################## | |||
## Java | |||
############################## | |||
.mtj.tmp/ | |||
*.class | |||
*.jar | |||
*.war | |||
*.ear | |||
*.nar | |||
hs_err_pid* | |||
############################## | |||
## Maven | |||
############################## | |||
target/ | |||
pom.xml.tag | |||
pom.xml.releaseBackup | |||
pom.xml.versionsBackup | |||
pom.xml.next | |||
pom.xml.bak | |||
release.properties | |||
dependency-reduced-pom.xml | |||
buildNumber.properties | |||
.mvn/timing.properties | |||
.mvn/wrapper/maven-wrapper.jar | |||
############################## | |||
## Gradle | |||
############################## | |||
bin/ | |||
build/ | |||
.gradle | |||
.gradletasknamecache | |||
gradle-app.setting | |||
!gradle-wrapper.jar | |||
############################## | |||
## IntelliJ | |||
############################## | |||
out/ | |||
.idea/ | |||
.idea_modules/ | |||
*.iml | |||
*.ipr | |||
*.iws | |||
############################## | |||
## Eclipse | |||
############################## | |||
.settings/ | |||
bin/ | |||
tmp/ | |||
.metadata | |||
.classpath | |||
.project | |||
*.tmp | |||
*.bak | |||
*.swp | |||
*~.nib | |||
local.properties | |||
.loadpath | |||
.factorypath | |||
############################## | |||
## NetBeans | |||
############################## | |||
nbproject/private/ | |||
build/ | |||
nbbuild/ | |||
dist/ | |||
nbdist/ | |||
nbactions.xml | |||
nb-configuration.xml | |||
############################## | |||
## Visual Studio Code | |||
############################## | |||
.vscode/ | |||
.code-workspace | |||
############################## | |||
## OS X | |||
############################## | |||
.DS_Store |
@@ -0,0 +1,61 @@ | |||
<project xmlns="http://maven.apache.org/POM/4.0.0" | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<groupId>com.mockitotutorial</groupId> | |||
<artifactId>happyhotel</artifactId> | |||
<version>0.0.1-SNAPSHOT</version> | |||
<name>Happy Hotel App</name> | |||
<description>A project to learn mockito</description> | |||
<properties> | |||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |||
<maven.compiler.source>11</maven.compiler.source> | |||
<maven.compiler.target>11</maven.compiler.target> | |||
</properties> | |||
<dependencies> | |||
<dependency> | |||
<groupId>org.junit.jupiter</groupId> | |||
<artifactId>junit-jupiter-engine</artifactId> | |||
<version>5.7.0</version> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.mockito</groupId> | |||
<artifactId>mockito-core</artifactId> | |||
<version>3.5.13</version> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.mockito</groupId> | |||
<artifactId>mockito-junit-jupiter</artifactId> | |||
<version>2.23.0</version> | |||
<scope>test</scope> | |||
</dependency> | |||
</dependencies> | |||
<build> | |||
<plugins> | |||
<plugin> | |||
<artifactId>maven-surefire-plugin</artifactId> | |||
<version>2.19.1</version> | |||
<dependencies> | |||
<dependency> | |||
<groupId>org.junit.platform</groupId> | |||
<artifactId>junit-platform-surefire-provider</artifactId> | |||
<version>1.0.1</version> | |||
</dependency> | |||
</dependencies> | |||
</plugin> | |||
<plugin> | |||
<groupId>org.apache.maven.plugins</groupId> | |||
<artifactId>maven-compiler-plugin</artifactId> | |||
<configuration> | |||
<source>8</source> | |||
<target>8</target> | |||
</configuration> | |||
</plugin> | |||
</plugins> | |||
</build> | |||
</project> |
@@ -0,0 +1,23 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
import java.util.*; | |||
public class BookingDAO { | |||
private final Map<String, BookingRequest> bookings = new HashMap<>(); | |||
public String save(BookingRequest bookingRequest) { | |||
String id = UUID.randomUUID().toString(); | |||
bookings.put(id, bookingRequest); | |||
return id; | |||
} | |||
public BookingRequest get(String id) { | |||
return bookings.get(id); | |||
} | |||
public void delete(String bookingId) { | |||
bookings.remove(bookingId); | |||
} | |||
} |
@@ -0,0 +1,101 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
import java.time.LocalDate; | |||
public class BookingRequest { | |||
private final String userId; | |||
private final LocalDate dateFrom; | |||
private final LocalDate dateTo; | |||
private final int guestCount; | |||
private final boolean prepaid; | |||
private String roomId; | |||
public BookingRequest(String userId, LocalDate dateFrom, LocalDate dateTo, int guestCount, boolean prepaid) { | |||
super(); | |||
this.userId = userId; | |||
this.dateFrom = dateFrom; | |||
this.dateTo = dateTo; | |||
this.guestCount = guestCount; | |||
this.prepaid = prepaid; | |||
} | |||
public String getUserId() { | |||
return userId; | |||
} | |||
public LocalDate getDateFrom() { | |||
return dateFrom; | |||
} | |||
public LocalDate getDateTo() { | |||
return dateTo; | |||
} | |||
public int getGuestCount() { | |||
return guestCount; | |||
} | |||
public boolean isPrepaid() { | |||
return prepaid; | |||
} | |||
public String getRoomId() { | |||
return roomId; | |||
} | |||
public void setRoomId(String roomId) { | |||
this.roomId = roomId; | |||
} | |||
@Override | |||
public int hashCode() { | |||
final int prime = 31; | |||
int result = 1; | |||
result = prime * result | |||
+ ((dateFrom == null) ? 0 : dateFrom.hashCode()); | |||
result = prime * result + ((dateTo == null) ? 0 : dateTo.hashCode()); | |||
result = prime * result + guestCount; | |||
result = prime * result + (prepaid ? 1231 : 1237); | |||
result = prime * result + ((roomId == null) ? 0 : roomId.hashCode()); | |||
result = prime * result + ((userId == null) ? 0 : userId.hashCode()); | |||
return result; | |||
} | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (this == obj) | |||
return true; | |||
if (obj == null) | |||
return false; | |||
if (getClass() != obj.getClass()) | |||
return false; | |||
BookingRequest other = (BookingRequest) obj; | |||
if (dateFrom == null) { | |||
if (other.dateFrom != null) | |||
return false; | |||
} else if (!dateFrom.equals(other.dateFrom)) | |||
return false; | |||
if (dateTo == null) { | |||
if (other.dateTo != null) | |||
return false; | |||
} else if (!dateTo.equals(other.dateTo)) | |||
return false; | |||
if (guestCount != other.guestCount) | |||
return false; | |||
if (prepaid != other.prepaid) | |||
return false; | |||
if (roomId == null) { | |||
if (other.roomId != null) | |||
return false; | |||
} else if (!roomId.equals(other.roomId)) | |||
return false; | |||
if (userId == null) { | |||
if (other.userId != null) | |||
return false; | |||
} else if (!userId.equals(other.userId)) | |||
return false; | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,61 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
import java.time.temporal.ChronoUnit; | |||
public class BookingService { | |||
private final PaymentService paymentService; | |||
private final RoomService roomService; | |||
private final BookingDAO bookingDAO; | |||
private final MailSender mailSender; | |||
private final static double BASE_PRICE_USD = 50.0; | |||
public int getAvailablePlaceCount() { | |||
return roomService.getAvailableRooms() | |||
.stream() | |||
.map(room -> room.getCapacity()) | |||
.reduce(0, Integer::sum); | |||
} | |||
public double calculatePrice(BookingRequest bookingRequest) { | |||
long nights = ChronoUnit.DAYS.between(bookingRequest.getDateFrom(), bookingRequest.getDateTo()); | |||
return BASE_PRICE_USD * bookingRequest.getGuestCount() * nights; | |||
} | |||
public double calculatePriceEuro(BookingRequest bookingRequest) { | |||
long nights = ChronoUnit.DAYS.between(bookingRequest.getDateFrom(), bookingRequest.getDateTo()); | |||
return CurrencyConverter.toEuro(BASE_PRICE_USD * bookingRequest.getGuestCount() * nights); | |||
} | |||
public String makeBooking(BookingRequest bookingRequest) { | |||
String roomId = roomService.findAvailableRoomId(bookingRequest); | |||
double price = calculatePrice(bookingRequest); | |||
if (bookingRequest.isPrepaid()) { | |||
paymentService.pay(bookingRequest, price); | |||
} | |||
bookingRequest.setRoomId(roomId); | |||
String bookingId = bookingDAO.save(bookingRequest); | |||
roomService.bookRoom(roomId); | |||
mailSender.sendBookingConfirmation(bookingId); | |||
return bookingId; | |||
} | |||
public void cancelBooking(String id) { | |||
BookingRequest request = bookingDAO.get(id); | |||
roomService.unbookRoom(request.getRoomId()); | |||
bookingDAO.delete(id); | |||
} | |||
public BookingService(PaymentService paymentService, RoomService roomService, BookingDAO bookingDAO, | |||
MailSender mailSender) { | |||
super(); | |||
this.paymentService = paymentService; | |||
this.roomService = roomService; | |||
this.bookingDAO = bookingDAO; | |||
this.mailSender = mailSender; | |||
} | |||
} |
@@ -0,0 +1,5 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
public class BusinessException extends RuntimeException { | |||
} |
@@ -0,0 +1,11 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
public class CurrencyConverter { | |||
private static final double USD_TO_EUR_RATE = 0.85; | |||
public static double toEuro(double dollarAmount) { | |||
return dollarAmount * USD_TO_EUR_RATE; | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
public class MailSender { | |||
public void sendBookingConfirmation(String bookingId) { | |||
// TODO Not done yet. John Smith to implement! | |||
throw new UnsupportedOperationException("Not implemented yet"); | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
import java.util.*; | |||
public class PaymentService { | |||
private final Map<String, Double> payments = new HashMap<>(); | |||
public String pay(BookingRequest bookingRequest, double price) { | |||
if (price > 200.0 && bookingRequest.getGuestCount() < 3) { | |||
throw new UnsupportedOperationException("Only small payments are supported."); | |||
} | |||
String id = UUID.randomUUID().toString(); | |||
payments.put(id, price); | |||
return id; | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
public class Room { | |||
private final String id; | |||
private final int capacity; | |||
public Room(String id, int capacity) { | |||
this.id = id; | |||
this.capacity = capacity; | |||
} | |||
public int getCapacity() { | |||
return capacity; | |||
} | |||
public String getId() { | |||
return id; | |||
} | |||
@Override | |||
public int hashCode() { | |||
final int prime = 31; | |||
int result = 1; | |||
result = prime * result + capacity; | |||
result = prime * result + ((id == null) ? 0 : id.hashCode()); | |||
return result; | |||
} | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (this == obj) | |||
return true; | |||
if (obj == null) | |||
return false; | |||
if (getClass() != obj.getClass()) | |||
return false; | |||
Room other = (Room) obj; | |||
if (capacity != other.capacity) | |||
return false; | |||
if (id == null) { | |||
if (other.id != null) | |||
return false; | |||
} else if (!id.equals(other.id)) | |||
return false; | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,58 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
import java.util.*; | |||
import java.util.stream.Collectors; | |||
public class RoomService { | |||
private final Map<Room, Boolean> roomAvailability; | |||
{ | |||
roomAvailability = new HashMap<>(); | |||
roomAvailability.put(new Room("1.1", 2), true); | |||
roomAvailability.put(new Room("1.2", 2), true); | |||
roomAvailability.put(new Room("1.3", 5), true); | |||
roomAvailability.put(new Room("2.1", 3), true); | |||
roomAvailability.put(new Room("2.2", 4), true); | |||
} | |||
public String findAvailableRoomId(BookingRequest bookingRequest) { | |||
return roomAvailability.entrySet().stream() | |||
.filter(entry -> entry.getValue()).map(entry -> entry.getKey()) | |||
.filter(room -> room.getCapacity() == bookingRequest.getGuestCount()) | |||
.findFirst() | |||
.map(room -> room.getId()) | |||
.orElseThrow(BusinessException::new); | |||
} | |||
public List<Room> getAvailableRooms() { | |||
return roomAvailability.entrySet().stream() | |||
.filter(entry -> entry.getValue()) | |||
.map(entry -> entry.getKey()) | |||
.collect(Collectors.toList()); | |||
} | |||
public int getRoomCount() { | |||
return roomAvailability.size(); | |||
} | |||
public void bookRoom(String roomId) { | |||
Room room = roomAvailability.entrySet().stream() | |||
.filter(entry -> entry.getKey().getId().equals(roomId) && entry.getValue()) | |||
.findFirst() | |||
.map(entry -> entry.getKey()) | |||
.orElseThrow(BusinessException::new); | |||
roomAvailability.put(room, true); | |||
} | |||
public void unbookRoom(String roomId) { | |||
Room room = roomAvailability.entrySet().stream() | |||
.filter(entry -> entry.getKey().getId().equals(roomId) && !entry.getValue()) | |||
.findFirst() | |||
.map(entry -> entry.getKey()) | |||
.orElseThrow(BusinessException::new); | |||
roomAvailability.put(room, false); | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
package com.mockitotutorial.happyhotel.booking; | |||
import org.junit.jupiter.api.Test; | |||
class Test00SanityCheck { | |||
@Test | |||
void test() { | |||
// should pass | |||
} | |||
} |