diff --git a/src/rental/InvalidRequestException.java b/src/rental/InvalidRequestException.java new file mode 100644 index 0000000..b8b67bd --- /dev/null +++ b/src/rental/InvalidRequestException.java @@ -0,0 +1,9 @@ +package rental; + +public class InvalidRequestException extends RuntimeException { + private static final long serialVersionUID = -3860346525962550742L; + + public InvalidRequestException(String message) { + super(message); + } +} diff --git a/src/rental/RentalPriceCalculator.java b/src/rental/RentalPriceCalculator.java index 43fdddf..c83f69d 100644 --- a/src/rental/RentalPriceCalculator.java +++ b/src/rental/RentalPriceCalculator.java @@ -1,43 +1,95 @@ package rental; public class RentalPriceCalculator { - - // age - age of driver - // licence - number of full years person holds driving licence - // clazz - class of the car from 1 (smallest) to 5 (largest) that person wishes to rent - // acc - has s/he caused any accidents within last year - // acc2 - has s/he participated (but not caused) in any accidents within last year - // season - if it is high season or not - public double price(int age, int licence, int clazz, boolean acc, boolean acc2, boolean season) { - - if (age < 18) { - throw new IllegalArgumentException("Driver too young - cannot quote the price"); - } - if (age <= 21 && clazz > 2) { - throw new UnsupportedOperationException("Drivers 21 y/o or less can only rent Class 1 vehicles"); + private static final double MAX_RENTAL_PRICE = 1000.0; + private static final int MINIMUM_YEARS_LICENSE_HELD = 1; + private static final int DRIVER_AGE_CUTOFF = 18; + + public double price(RentalRequest request) throws InvalidRequestException + { + validateRequest(request); + double rentalEstimate = getRentalEstimate(request); + return getPriceFromEstimate(rentalEstimate); + } + + void validateRequest(RentalRequest request) throws InvalidRequestException { + if (!isDriverOldEnough(request)) { + throw new InvalidRequestException( + "Driver too young - cannot quote the price"); } - double rentalprice = age; + if (!hasLicenseBeenHeldLongEnough(request)) { + throw new InvalidRequestException( + "Driver has not held a license for long enough. Can not rent a car!"); + } - if (clazz >=4 && age <= 25 && season != false) { - rentalprice = rentalprice * 2; + if (!isVehicleAllowedForDriverAge(request)) { + throw new InvalidRequestException( + "The vehicle class is not suitable for the driver's age"); } + } + + boolean isDriverOldEnough(RentalRequest request) { + return request.getDriverAge() >= DRIVER_AGE_CUTOFF; + } + + boolean hasLicenseBeenHeldLongEnough(RentalRequest request) { + return request.getYearsLicenseHeld() >= MINIMUM_YEARS_LICENSE_HELD; + } + + double getRentalEstimate(RentalRequest request) { + double rentalEstimate = getInitialEstimate(request); + + rentalEstimate = adjustEstimateForSeason(rentalEstimate, request); + rentalEstimate = adjustEstimateForLicenseHeld(rentalEstimate, request); + rentalEstimate = adjustEstimateForAccidentStatus(rentalEstimate, request); + + return rentalEstimate; + } + + double getInitialEstimate(RentalRequest request) { + return request.getDriverAge(); + } + + double adjustEstimateForSeason(double rentalEstimate, RentalRequest request) + { + VehicleClass vehicleClass = request.getVehicleClass(); - if (licence < 1) { - throw new IllegalArgumentException("Driver must hold driving licence at least for one year. Can not rent a car!"); + if ((vehicleClass == VehicleClass.FOURTH_CLASS || vehicleClass == VehicleClass.FIFTH_CLASS) + && request.getDriverAge() <= 25 + && !request.isHighSeason()) { + rentalEstimate = rentalEstimate * 2; } - if (licence < 3) { - rentalprice = rentalprice * 1.3; + return rentalEstimate; + } + + double adjustEstimateForLicenseHeld(double rentalEstimate, RentalRequest request) { + if (request.getYearsLicenseHeld() < 3) { + rentalEstimate = rentalEstimate * 1.3; } - if (acc == true && age < 30) { - rentalprice += 15; + return rentalEstimate; + } + + double adjustEstimateForAccidentStatus(double rentalEstimate, RentalRequest request) { + if (request.hasCausedAccidentsWithinLastYear() + && request.getDriverAge() < 30) { + rentalEstimate += 15; } + + return rentalEstimate; + } - if (rentalprice > 1000) { - return 1000.00; + boolean isVehicleAllowedForDriverAge(RentalRequest request) { + if (request.getDriverAge() <= 21) { + return request.getVehicleClass() == VehicleClass.FIRST_CLASS; } - return rentalprice; + + return true; + } + + double getPriceFromEstimate(double rentalEstimate) { + return Math.min(rentalEstimate, MAX_RENTAL_PRICE); } } \ No newline at end of file diff --git a/src/rental/RentalRequest.java b/src/rental/RentalRequest.java new file mode 100644 index 0000000..6283f0c --- /dev/null +++ b/src/rental/RentalRequest.java @@ -0,0 +1,55 @@ +package rental; + +public class RentalRequest { + private int driverAge; + private int yearsLicenseHeld; + private VehicleClass vehicleClass; + private boolean hasCausedAccidentsWithinLastYear; + private boolean hasParticipatedInAccidentsWithinLastYear; + private boolean isHighSeason; + + public int getDriverAge() { + return driverAge; + } + + public int getYearsLicenseHeld() { + return yearsLicenseHeld; + } + + public VehicleClass getVehicleClass() { + return vehicleClass; + } + + public boolean hasCausedAccidentsWithinLastYear() { + return hasCausedAccidentsWithinLastYear; + } + + public boolean hasParticipatedInAccidentsWithinLastYear() { + return hasParticipatedInAccidentsWithinLastYear; + } + + public void hasParticipatedInAccidentsWithinLastYear( + boolean hasParticipatedInAccidentsWithinLastYear) { + this.hasParticipatedInAccidentsWithinLastYear = hasParticipatedInAccidentsWithinLastYear; + } + + public boolean isHighSeason() { + return isHighSeason; + } + + public RentalRequest( + int driverAge, + int yearsLicenseHeld, + VehicleClass vehicleClass, + boolean hasCausedAccidentsWithinLastYear, + boolean hasParticipatedInAccidentsWithinLastYear, + boolean isHighSeason) { + super(); + this.driverAge = driverAge; + this.yearsLicenseHeld = yearsLicenseHeld; + this.vehicleClass = vehicleClass; + this.hasCausedAccidentsWithinLastYear = hasCausedAccidentsWithinLastYear; + this.hasParticipatedInAccidentsWithinLastYear = hasParticipatedInAccidentsWithinLastYear; + this.isHighSeason = isHighSeason; + } +} diff --git a/src/rental/VehicleClass.java b/src/rental/VehicleClass.java new file mode 100644 index 0000000..ea17df1 --- /dev/null +++ b/src/rental/VehicleClass.java @@ -0,0 +1,9 @@ +package rental; + +public enum VehicleClass { + FIRST_CLASS, + SECOND_CLASS, + THIRD_CLASS, + FOURTH_CLASS, + FIFTH_CLASS +} diff --git a/test/rental/RentalPriceCalculatorTest.java b/test/rental/RentalPriceCalculatorTest.java index 6654c4c..cb2ef46 100644 --- a/test/rental/RentalPriceCalculatorTest.java +++ b/test/rental/RentalPriceCalculatorTest.java @@ -1,19 +1,81 @@ package rental; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class RentalPriceCalculatorTest { + RentalPriceCalculator calculator = new RentalPriceCalculator(); @Before public void beforeEachTest() { // this method is called before each test } + @Test(expected=InvalidRequestException.class) + public void testUnder18NotAllowed() { + RentalRequest request = new RentalRequest( + 17, 10, VehicleClass.FIRST_CLASS, false, false, false); + calculator.validateRequest(request); + } + + @Test(expected=InvalidRequestException.class) + public void testLicenseNotHeldLongEnough() { + RentalRequest request = new RentalRequest( + 17, 0, VehicleClass.FIRST_CLASS, false, false, false); + calculator.validateRequest(request); + } + + @Test(expected=InvalidRequestException.class) + public void testUnder21SecondClassNotAllowed() { + RentalRequest request = new RentalRequest( + 19, 0, VehicleClass.SECOND_CLASS, false, false, false); + calculator.validateRequest(request); + } + + @Test(expected=InvalidRequestException.class) + public void testUnder21ThirdClassNotAllowed() { + RentalRequest request = new RentalRequest( + 19, 0, VehicleClass.THIRD_CLASS, false, false, false); + calculator.validateRequest(request); + } + + @Test(expected=InvalidRequestException.class) + public void testUnder21FourthClassNotAllowed() { + RentalRequest request = new RentalRequest( + 19, 0, VehicleClass.FOURTH_CLASS, false, false, false); + calculator.validateRequest(request); + } + + @Test(expected=InvalidRequestException.class) + public void testUnder21FifthClassNotAllowed() { + RentalRequest request = new RentalRequest( + 19, 0, VehicleClass.FIFTH_CLASS, false, false, false); + calculator.validateRequest(request); + } + + @Test + public void testPriceRemainsSameFor5YearsOfExperience() { + RentalRequest request = new RentalRequest( + 19, 5, VehicleClass.FIRST_CLASS, false, false, false); + assertEquals(100, calculator.adjustEstimateForLicenseHeld(100, request), 0.0001); + } + + @Test + public void testInitialPriceIsDriverAge() { + RentalRequest request = new RentalRequest( + 19, 5, VehicleClass.FIRST_CLASS, false, false, false); + assertEquals(19, calculator.getInitialEstimate(request), 0.0001); + } + + @Test + public void testMaxPriceIs1000() { + assertEquals(1000.0, calculator.getPriceFromEstimate(1500.0), 0.0001); + } + @Test - public void test() { - fail("Not yet implemented"); + public void testPriceLessThan1000() { + assertEquals(900.0, calculator.getPriceFromEstimate(900.0), 0.0001); } -} +} \ No newline at end of file