Skip to content
Snippets Groups Projects
Commit d01f6fff authored by LABOUREL Arnaud's avatar LABOUREL Arnaud
Browse files

Correction composition

parent 70f481de
Branches main
No related tags found
No related merge requests found
Pipeline #6014 passed
rootProject.name = 'formula'
rootProject.name = 'agency'
......@@ -33,8 +33,8 @@ public abstract class AbstractVehicle implements Vehicle {
if(productionYear < MINIMAL_YEAR_VALUE || productionYear > currentYearValue)
throw new IllegalArgumentException(productionYear + " is not a correct year (comprised between "
+ MINIMAL_YEAR_VALUE + " and " + currentYearValue + ")");
this.brand = brand;
this.productionYear = productionYear;
this.brand = brand;
this.model = model;
}
......
package agency;
import util.TimeProvider;
public class CarSpecifics implements VehicleTypeSpecifics {
private static final int MAXIMUM_AGE_FOR_NEW_CAR = 5;
private final int numberOfSeats;
private static final int PRICE_PER_SEAT_FOR_NEW_CAR = 40;
private static final int PRICE_PER_SEAT_FOR_OLD_CAR = 20;
private final boolean isNew;
public CarSpecifics(int numberOfSeats, int productionYear) {
isNew = age(productionYear) <= MAXIMUM_AGE_FOR_NEW_CAR;
this.numberOfSeats = numberOfSeats;
if (numberOfSeats < 1)
throw new IllegalArgumentException("Cannot construct a car with "
+ numberOfSeats + " seats");
}
private static int age(int productionYear) {
return TimeProvider.currentYearValue() - productionYear;
}
@Override
public double dailyRentalPrice() {
final int priceBySeat = isNew ? PRICE_PER_SEAT_FOR_NEW_CAR : PRICE_PER_SEAT_FOR_OLD_CAR;
return priceBySeat * numberOfSeats;
}
@Override
public String kindOfVehicle() {
return "Car";
}
@Override
public String vehicleDetails() {
return numberOfSeats + " " + (hasSeveralSeats() ? "seats" : "seat");
}
private boolean hasSeveralSeats() {
return numberOfSeats > 1;
}
}
......@@ -6,7 +6,6 @@ public class Client {
private final String firstName;
private final String lastName;
private final int yearOfBirth;
public Client(String firstName, String lastName, int yearOfBirth) {
this.firstName = firstName;
this.lastName = lastName;
......
package agency;
import util.TimeProvider;
public class ConcreteVehicle implements Vehicle{
private static final int MINIMAL_YEAR_VALUE = 1900;
private final String brand;
private final String model;
private final int productionYear;
private final VehicleTypeSpecifics vehicleTypeSpecifics;
@Override
public int hashCode() {
int result = brand.hashCode();
result = 31 * result + model.hashCode();
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || this.getClass() != o.getClass()) return false;
ConcreteVehicle that = (ConcreteVehicle) o;
if (vehicleTypeSpecifics.getClass() != that.vehicleTypeSpecifics.getClass())
return false;
if (!brand.equals(that.brand)) return false;
return model.equals(that.model);
}
ConcreteVehicle(String brand, String model, int productionYear,
VehicleTypeSpecifics vehicleTypeSpecifics) {
int currentYearValue = TimeProvider.currentYearValue();
if(productionYear < MINIMAL_YEAR_VALUE || productionYear > currentYearValue)
throw new IllegalArgumentException(productionYear + " is not a correct year (comprised between "
+ MINIMAL_YEAR_VALUE + " and " + currentYearValue + ")");
this.productionYear = productionYear;
this.brand = brand;
this.model = model;
this.vehicleTypeSpecifics = vehicleTypeSpecifics;
}
@Override
public String getBrand() {
return brand;
}
@Override
public String getModel() {
return model;
}
@Override
public int getProductionYear() {
return productionYear;
}
public String kindOfVehicle(){
return vehicleTypeSpecifics.kindOfVehicle();
}
public String vehicleDetails(){
return vehicleTypeSpecifics.vehicleDetails();
}
@Override
public double dailyRentalPrice() {
return vehicleTypeSpecifics.dailyRentalPrice();
}
@Override
public String toString() {
return kindOfVehicle() + " " + brand + " " + model + " " + productionYear
+ " (" + vehicleDetails() + ")" + " : "
+ dailyRentalPrice() + "€";
}
}
package agency;
public class MotorbikeSpecifics implements VehicleTypeSpecifics{
private static final double PRICE_PER_UNIT_OF_CYLINDER_CAPACITY = 0.25;
private static final int MINIMAL_CAPACITY = 50;
private static final String UNIT_OF_CYLINDER_CAPACITY = "cm³";
private final int cylinderCapacity;
MotorbikeSpecifics(int cylinderCapacity) {
if (!(cylinderCapacity < MINIMAL_CAPACITY))
throw new IllegalArgumentException("Incorrect cylinder capacity "+ cylinderCapacity + "(must be at least " + MINIMAL_CAPACITY +")");
this.cylinderCapacity = cylinderCapacity;
}
@Override
public String kindOfVehicle() {
return "Motorbike";
}
@Override
public String vehicleDetails() {
return cylinderCapacity + UNIT_OF_CYLINDER_CAPACITY;
}
@Override
public double dailyRentalPrice() {
return cylinderCapacity * PRICE_PER_UNIT_OF_CYLINDER_CAPACITY;
}
}
......@@ -7,6 +7,13 @@ public class RentalAgency {
private final List<Vehicle> vehicles = new ArrayList<>();
private final Map<Client, Vehicle> rentedVehicles = new HashMap<>();
public RentalAgency() {
}
public RentalAgency(List<Vehicle> vehicles) {
this.vehicles.addAll(vehicles);
}
void remove(Vehicle vehicle){
requiresExisting(vehicle);
vehicles.remove(vehicle);
......@@ -81,9 +88,12 @@ public class RentalAgency {
return vehicles;
}
public void printVehicles(){
private static void print(List<Vehicle> vehicles){
for(Vehicle vehicle : vehicles){
System.out.println(vehicle);
}
}
public void printSelectedVehicles(Predicate<Vehicle> criterion){
print(select(criterion));
}
}
package agency;
public interface VehicleTypeSpecifics {
String kindOfVehicle();
String vehicleDetails();
double dailyRentalPrice();
}
......@@ -2,92 +2,118 @@ package agency;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import util.TimeProvider;
import java.time.LocalDateTime;
import java.util.Objects;
import static org.assertj.core.api.Assertions.*;
class TestRentalAgency extends TestCar{
private RentalAgency rentalAgency;
Car catalinaCar = new Car(apple, catalina, catalinaYear, catalinaNumberOfSeats);
Car windows95Car = new Car(microsoft, windows95, windows95Year, windows95NumberOfSeats);
static final String apple = "Apple";
static final String catalina = "Catalina";
static final String microsoft = "Microsoft";
static final String windows95 = "Windows95";
static final int catalinaYear = 2019;
static final int windows95Year = 1995;
static final int catalinaNumberOfSeats = 3;
private static final int windows95NumberOfSeats = 1;
private static final LocalDateTime YEAR2000 = LocalDateTime.of(2000, 1, 1, 0, 0);
private static final LocalDateTime YEAR2019 = LocalDateTime.of(2019, 1, 1, 0, 0);
@BeforeEach
void initializeRentalAgency(){
rentalAgency = new RentalAgency();
void fixClock(){
TimeProvider.useFixedClockAt(YEAR2019);
}
@Test
void testAddingCars(){
rentalAgency.add(catalinaCar);
assertThat(rentalAgency.getVehicles())
.containsExactly(catalinaCar);
rentalAgency.add(windows95Car);
assertThat(rentalAgency.getVehicles())
.containsExactly(catalinaCar, windows95Car);
void testConstructionOfTooOldVehicle(){
assertThatIllegalArgumentException()
.isThrownBy(()->new Car("Linux", "ubuntu",1899, 3))
.withMessageContaining("1899");
}
@Test
void testAddingSameCar() {
assertThat(rentalAgency.add(catalinaCar)).isTrue();
assertThat(rentalAgency.add(catalinaCar)).isFalse();
void testConstructionOfFutureVehicle() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new Car("Linux", "ubuntu", 2020, 3))
.withMessageContaining("2020");
}
@Test
void testRemovingExistingVehicle(){
rentalAgency.add(catalinaCar);
rentalAgency.remove(catalinaCar);
assertThat(rentalAgency.getVehicles()).doesNotContain(catalinaCar);
void testConstructionOfVehicleWithNoSeats() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new Car("Linux", "ubuntu", 2000, 0))
.withMessageContaining("0");
}
@Test
void testRemovingNonExistingVehicle(){
assertThatThrownBy(() -> rentalAgency.remove(catalinaCar))
.isInstanceOf(UnknownVehicleException.class)
.hasMessageContaining(catalinaCar.toString());
void testGetters() {
assertThat(catalinaCar).hasFieldOrPropertyWithValue("brand", apple)
.hasFieldOrPropertyWithValue("model", catalina)
.hasFieldOrPropertyWithValue("productionYear", catalinaYear)
.hasFieldOrPropertyWithValue("numberOfSeats", catalinaNumberOfSeats);
}
@Test
void testSelect(){
rentalAgency.add(catalinaCar);
rentalAgency.add(windows95Car);
assertThat(rentalAgency.select(vehicle -> vehicle.getBrand().equals(apple)))
.containsExactly(catalinaCar);
assertThat(rentalAgency.select(vehicle -> vehicle.getModel().equals(windows95)))
.containsExactly(windows95Car);
void testConstructionOfFutureCar(){
assertThatIllegalArgumentException().
isThrownBy(() -> new Car("Linux", "ubuntu",
2020, 2));
}
private final Client arnaud = new Client("Arnaud", "Labourel", 1981);
private final Client paul = new Client("Paul", "Calcul", 2018);
@Test
void testRentingVehicles(){
rentalAgency.add(catalinaCar);
rentalAgency.add(windows95Car);
rentalAgency.rentVehicle(arnaud, catalinaCar);
rentalAgency.rentVehicle(paul, windows95Car);
assertThat(rentalAgency.allRentedVehicles()).containsExactly(catalinaCar, windows95Car);
void testConstructionOfTooOldCar(){
assertThatIllegalArgumentException().
isThrownBy(() -> new Car("Linux", "ubuntu",
1899, 1));
}
@Test
void testSameClientRentingSeveralVehicles(){
rentalAgency.add(catalinaCar);
rentalAgency.add(windows95Car);
assertThat(rentalAgency.rentVehicle(arnaud, catalinaCar)).isEqualTo(120.);
assertThatIllegalStateException().isThrownBy(() -> rentalAgency.rentVehicle(arnaud, windows95Car));
void testThatCarImplementsVehicle(){
assertThat(catalinaCar).withFailMessage("%s must implement %s",
Car.class, Vehicle.class)
.isInstanceOf(Vehicle.class);
}
@Test
void testSameVehicleRentedTwice(){
rentalAgency.add(catalinaCar);
rentalAgency.rentVehicle(arnaud, catalinaCar);
assertThatIllegalStateException().isThrownBy(() -> rentalAgency.rentVehicle(paul, catalinaCar));
void testIsNew(){
assertThat(windows95Car).withFailMessage("A car with production year %s should have been old",
windows95Year)
.returns(false, Car::isNew);
assertThat(catalinaCar).withFailMessage("A car with production year %s should have been new",
catalinaYear)
.returns(true, Car::isNew);
TimeProvider.useFixedClockAt(YEAR2000);
assertThat(windows95Car).withFailMessage("A car with production year %s should have been new in %s",
windows95Year, YEAR2000)
.returns(true, Car::isNew);
TimeProvider.useFixedClockAt(YEAR2019);
}
@Test
void testDailyRentalPrice(){
double expectedPriceCatalinaCar = 40.*catalinaNumberOfSeats;
double expectedPriceWindowsCar = 20.*windows95NumberOfSeats;
assertThat(catalinaCar).as("Car DailyRentalPrice")
.withFailMessage("A new car with %s seats must have price %s",
catalinaNumberOfSeats, expectedPriceCatalinaCar )
.returns(expectedPriceCatalinaCar, Car::dailyRentalPrice);
assertThat(windows95Car).as("Car DailyRentalPrice")
.withFailMessage("An old car with %s seat must have price %s",
windows95NumberOfSeats, expectedPriceCatalinaCar )
.returns(expectedPriceWindowsCar, Car::dailyRentalPrice);
}
@Test
void testRentingAVehicleNotInTheAgency(){
assertThatThrownBy(() -> rentalAgency.rentVehicle(paul, catalinaCar))
.isInstanceOf(UnknownVehicleException.class)
.hasMessageContaining(catalinaCar.toString());
void testToString(){
String expectedStringMacOs = "Car Apple Catalina 2019 (3 seats) : 120.0€";
assertThat(catalinaCar).returns(expectedStringMacOs, Objects::toString);
String expectedStringWin = "Car Microsoft Windows95 1995 (1 seat) : 20.0€";
assertThat(windows95Car).returns(expectedStringWin, Objects::toString);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment