This commit is contained in:
2026-05-18 16:58:51 +02:00
commit 3c468a1b59
19 changed files with 1078 additions and 0 deletions

17
source/.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
# Maven build output
target/
# Generated log files
*.log
# IDE files
.idea/
*.iml
.vscode/
*.classpath
*.project
.settings/
# OS files
.DS_Store
Thumbs.db

51
source/pom.xml Normal file
View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>se.kth.iv1350</groupId>
<artifactId>repairbike</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main</sourceDirectory>
<testSourceDirectory>src/test</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>startup.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,88 @@
package controller;
import integration.BikeRegistry;
import integration.RepairTaskCatalog;
import model.Amount;
import model.BikeDTO;
import model.RepairOrder;
import model.RepairShop;
import model.TaskDTO;
/**
* Coordinates use-case execution between the view and the model and integration layers.
* All calls from the view pass through this class.
*/
public class Controller {
private final RepairShop repairShop;
private final BikeRegistry bikeRegistry;
private final RepairTaskCatalog taskCatalog;
/**
* Creates a Controller wired to the given dependencies.
*
* @param repairShop The repair shop facade (model layer).
* @param bikeRegistry The bike registry (integration layer).
* @param taskCatalog The repair task catalog (integration layer).
*/
public Controller(RepairShop repairShop, BikeRegistry bikeRegistry,
RepairTaskCatalog taskCatalog) {
this.repairShop = repairShop;
this.bikeRegistry = bikeRegistry;
this.taskCatalog = taskCatalog;
}
/**
* Starts a new repair session.
*/
public void startNewRepair() {
repairShop.startRepair();
}
/**
* Registers the bike with the given ID for the current repair session.
*
* @param bikeID The unique identifier of the bike to register.
* @return The {@link BikeDTO} of the registered bike, or {@code null} if the
* bike ID does not exist in the registry.
*/
public BikeDTO enterBikeID(String bikeID) {
BikeDTO bike = bikeRegistry.findBike(bikeID);
if (bike != null) {
repairShop.registerBike(bike);
}
return bike;
}
/**
* Adds the repair task with the given name to the current repair session.
*
* @param taskName The name of the repair task to add.
* @return The updated running total as an {@link Amount}, or {@code null} if the
* task name does not exist in the catalog.
*/
public Amount addRepairTask(String taskName) {
TaskDTO task = taskCatalog.findTask(taskName);
if (task != null) {
return repairShop.addTask(task);
}
return null;
}
/**
* Records the mechanic's diagnostic notes for the current repair session.
*
* @param report The diagnostic report text entered by the mechanic.
*/
public void enterDiagnosticReport(String report) {
repairShop.enterDiagnosticReport(report);
}
/**
* Ends the current repair session and returns the completed repair order.
*
* @return The {@link RepairOrder} summarising all repair details.
*/
public RepairOrder endRepair() {
return repairShop.endRepair();
}
}

View File

@@ -0,0 +1,34 @@
package integration;
import model.BikeDTO;
import java.util.HashMap;
import java.util.Map;
/**
* Handles retrieval of bike information from persistent storage.
* In this implementation, bikes are stored in memory as sample data.
*/
public class BikeRegistry {
private final Map<String, BikeDTO> bikes = new HashMap<>();
/**
* Creates a BikeRegistry pre-loaded with sample bike records.
*/
public BikeRegistry() {
bikes.put("BIKE-001", new BikeDTO("BIKE-001", "Alice Svensson"));
bikes.put("BIKE-002", new BikeDTO("BIKE-002", "Bob Lindqvist"));
bikes.put("BIKE-003", new BikeDTO("BIKE-003", "Carl Johansson"));
}
/**
* Looks up and returns the bike with the given ID.
*
* @param bikeID The unique identifier of the bike to look up.
* @return The {@link BikeDTO} for the found bike, or {@code null} if no bike
* with the given ID exists in the registry.
*/
public BikeDTO findBike(String bikeID) {
return bikes.get(bikeID);
}
}

View File

@@ -0,0 +1,40 @@
package integration;
import model.Amount;
import model.TaskDTO;
import java.util.HashMap;
import java.util.Map;
/**
* Handles retrieval of repair task information from persistent storage.
* In this implementation, tasks are stored in memory as sample data.
*/
public class RepairTaskCatalog {
private final Map<String, TaskDTO> tasks = new HashMap<>();
/**
* Creates a RepairTaskCatalog pre-loaded with sample repair task records.
*/
public RepairTaskCatalog() {
tasks.put("Brake Pad Replacement",
new TaskDTO("Brake Pad Replacement", new Amount(350.00)));
tasks.put("Tire Replacement",
new TaskDTO("Tire Replacement", new Amount(500.00)));
tasks.put("Battery Check",
new TaskDTO("Battery Check", new Amount(200.00)));
tasks.put("Chain Lubrication",
new TaskDTO("Chain Lubrication", new Amount(150.00)));
}
/**
* Looks up and returns the repair task with the given name.
*
* @param taskName The name of the repair task to look up.
* @return The {@link TaskDTO} for the found task, or {@code null} if no task
* with the given name exists in the catalog.
*/
public TaskDTO findTask(String taskName) {
return tasks.get(taskName);
}
}

View File

@@ -0,0 +1,64 @@
package model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Represents one ongoing repair session for a single bike.
* Only accessible within the model package via {@link RepairShop}.
*/
class ActiveRepair {
private BikeDTO bike;
private final List<TaskDTO> tasks = new ArrayList<>();
private String diagnosticReport = "";
private Amount total = new Amount(0);
/**
* Registers the bike that is being repaired in this session.
*
* @param bike The bike to register.
*/
void registerBike(BikeDTO bike) {
this.bike = bike;
}
/**
* Adds a repair task to this session and returns the updated running total.
*
* @param task The repair task to add.
* @return The new running total after adding the task.
*/
Amount addTask(TaskDTO task) {
tasks.add(task);
total = calculateTotal();
return total;
}
/**
* Records the mechanic's diagnostic notes for this repair session.
*
* @param report The diagnostic report text entered by the mechanic.
*/
void enterDiagnosticReport(String report) {
this.diagnosticReport = report;
}
/**
* Ends the repair session and returns a completed repair order.
*
* @return The {@link RepairOrder} summarising all repair details.
*/
RepairOrder endRepair() {
List<TaskDTO> immutableTasks = Collections.unmodifiableList(new ArrayList<>(tasks));
return new RepairOrder(bike, immutableTasks, diagnosticReport, total);
}
private Amount calculateTotal() {
Amount sum = new Amount(0);
for (TaskDTO task : tasks) {
sum = sum.add(task.getCost());
}
return sum;
}
}

View File

@@ -0,0 +1,56 @@
package model;
/**
* Represents a monetary amount. Immutable; all arithmetic returns new instances.
*/
public class Amount {
private final double value;
/**
* Creates an Amount with the specified value.
*
* @param value The monetary value.
*/
public Amount(double value) {
this.value = value;
}
/**
* Returns a new Amount that is the sum of this amount and the given amount.
*
* @param other The amount to add.
* @return A new Amount representing the sum.
*/
public Amount add(Amount other) {
return new Amount(this.value + other.value);
}
/**
* Returns a new Amount that is the difference of this amount minus the given amount.
*
* @param other The amount to subtract.
* @return A new Amount representing the difference.
*/
public Amount subtract(Amount other) {
return new Amount(this.value - other.value);
}
/**
* Returns the raw numeric value of this amount.
*
* @return The monetary value as a double.
*/
public double getValue() {
return value;
}
/**
* Returns a formatted string representation of this amount.
*
* @return A string in the form {@code "123.45 SEK"}.
*/
@Override
public String toString() {
return String.format("%.2f SEK", value);
}
}

View File

@@ -0,0 +1,39 @@
package model;
/**
* Data Transfer Object that carries bike information across layer boundaries.
* Instances are immutable.
*/
public class BikeDTO {
private final String bikeID;
private final String ownerName;
/**
* Creates a BikeDTO with the specified bike ID and owner name.
*
* @param bikeID The unique identifier of the bike.
* @param ownerName The full name of the bike's owner.
*/
public BikeDTO(String bikeID, String ownerName) {
this.bikeID = bikeID;
this.ownerName = ownerName;
}
/**
* Returns the bike's unique identifier.
*
* @return The bike ID string.
*/
public String getBikeID() {
return bikeID;
}
/**
* Returns the full name of the bike's owner.
*
* @return The owner's name.
*/
public String getOwnerName() {
return ownerName;
}
}

View File

@@ -0,0 +1,65 @@
package model;
import java.util.List;
/**
* Represents a completed repair order issued at the end of a repair session.
* Instances are immutable.
*/
public class RepairOrder {
private final BikeDTO bike;
private final List<TaskDTO> tasks;
private final String diagnosticReport;
private final Amount total;
/**
* Creates a RepairOrder with all details of the completed repair.
*
* @param bike The bike that was repaired.
* @param tasks The list of repair tasks performed.
* @param diagnosticReport The mechanic's diagnostic notes.
* @param total The total cost of all repair tasks.
*/
RepairOrder(BikeDTO bike, List<TaskDTO> tasks, String diagnosticReport, Amount total) {
this.bike = bike;
this.tasks = tasks;
this.diagnosticReport = diagnosticReport;
this.total = total;
}
/**
* Returns the bike information for this repair order.
*
* @return The {@link BikeDTO} of the repaired bike.
*/
public BikeDTO getBike() {
return bike;
}
/**
* Returns the list of repair tasks included in this order.
*
* @return An unmodifiable list of {@link TaskDTO} objects.
*/
public List<TaskDTO> getTasks() {
return tasks;
}
/**
* Returns the mechanic's diagnostic report for this repair.
*
* @return The diagnostic report string.
*/
public String getDiagnosticReport() {
return diagnosticReport;
}
/**
* Returns the total cost of all repair tasks in this order.
*
* @return The total as an {@link Amount}.
*/
public Amount getTotal() {
return total;
}
}

View File

@@ -0,0 +1,60 @@
package model;
/**
* Facade for the model layer. Manages the lifecycle of one repair session at a time
* and delegates all operations to the current {@link ActiveRepair}.
*/
public class RepairShop {
private ActiveRepair currentRepair;
/**
* Creates a new RepairShop ready to accept repair sessions.
*/
public RepairShop() {
}
/**
* Starts a new repair session, discarding any previously active session.
*/
public void startRepair() {
currentRepair = new ActiveRepair();
}
/**
* Registers the bike that will be worked on during the current repair session.
*
* @param bike The {@link BikeDTO} of the bike to register.
*/
public void registerBike(BikeDTO bike) {
currentRepair.registerBike(bike);
}
/**
* Adds a repair task to the current session and returns the updated running total.
*
* @param task The {@link TaskDTO} of the task to add.
* @return The running total after the task has been added.
*/
public Amount addTask(TaskDTO task) {
return currentRepair.addTask(task);
}
/**
* Records the mechanic's diagnostic notes for the current repair session.
*
* @param report The diagnostic report text entered by the mechanic.
*/
public void enterDiagnosticReport(String report) {
currentRepair.enterDiagnosticReport(report);
}
/**
* Ends the current repair session and returns the completed repair order.
*
* @return The {@link RepairOrder} for the finished repair.
*/
public RepairOrder endRepair() {
return currentRepair.endRepair();
}
}

View File

@@ -0,0 +1,39 @@
package model;
/**
* Data Transfer Object that carries repair task information across layer boundaries.
* Instances are immutable.
*/
public class TaskDTO {
private final String name;
private final Amount cost;
/**
* Creates a TaskDTO with the specified task name and cost.
*
* @param name The name of the repair task.
* @param cost The cost of the repair task.
*/
public TaskDTO(String name, Amount cost) {
this.name = name;
this.cost = cost;
}
/**
* Returns the repair task name.
*
* @return The task name string.
*/
public String getName() {
return name;
}
/**
* Returns the cost of this repair task.
*
* @return The cost as an {@link Amount}.
*/
public Amount getCost() {
return cost;
}
}

View File

@@ -0,0 +1,28 @@
package startup;
import controller.Controller;
import integration.BikeRegistry;
import integration.RepairTaskCatalog;
import model.RepairShop;
import view.View;
/**
* Contains the application entry point. Responsible for creating and wiring
* all top-level objects in dependency order.
*/
public class Main {
/**
* Starts the Repair Electric Bike application.
*
* @param args Command-line arguments (not used).
*/
public static void main(String[] args) {
BikeRegistry bikeRegistry = new BikeRegistry();
RepairTaskCatalog taskCatalog = new RepairTaskCatalog();
RepairShop repairShop = new RepairShop();
Controller controller = new Controller(repairShop, bikeRegistry, taskCatalog);
View view = new View(controller);
view.runFakeExecution();
}
}

View File

@@ -0,0 +1,83 @@
package view;
import controller.Controller;
import model.Amount;
import model.BikeDTO;
import model.RepairOrder;
import model.TaskDTO;
/**
* Placeholder view that simulates mechanic interactions using hard-coded method calls.
* Everything returned by the controller is printed to standard output.
*/
public class View {
private final Controller controller;
/**
* Creates a View connected to the given controller.
*
* @param controller The controller to use for all system operations.
*/
public View(Controller controller) {
this.controller = controller;
}
/**
* Simulates a complete repair session using hard-coded inputs, printing all
* output returned by the controller to standard output.
*/
public void runFakeExecution() {
System.out.println("=== Repair Electric Bike System ===");
System.out.println();
controller.startNewRepair();
System.out.println("[Mechanic] Started new repair session.");
BikeDTO bike = controller.enterBikeID("BIKE-001");
if (bike != null) {
System.out.println("[System] Bike registered: ID=" + bike.getBikeID()
+ ", Owner=" + bike.getOwnerName());
} else {
System.out.println("[System] Bike not found.");
}
String[] taskNames = {"Brake Pad Replacement", "Tire Replacement"};
for (String taskName : taskNames) {
Amount runningTotal = controller.addRepairTask(taskName);
if (runningTotal != null) {
System.out.println("[System] Added task: \"" + taskName
+ "\" | Running total: " + runningTotal);
} else {
System.out.println("[System] Task not found: \"" + taskName + "\"");
}
}
String diagnosticNotes = "Front brake pads fully worn. Front tire flat (puncture). "
+ "Both parts replaced. Bike tested and approved.";
controller.enterDiagnosticReport(diagnosticNotes);
System.out.println("[Mechanic] Diagnostic report entered.");
RepairOrder repairOrder = controller.endRepair();
printRepairOrder(repairOrder);
}
private void printRepairOrder(RepairOrder repairOrder) {
System.out.println();
System.out.println("========================================");
System.out.println(" REPAIR ORDER ");
System.out.println("========================================");
System.out.println("Bike ID : " + repairOrder.getBike().getBikeID());
System.out.println("Owner : " + repairOrder.getBike().getOwnerName());
System.out.println("----------------------------------------");
System.out.println("Repair Tasks:");
for (TaskDTO task : repairOrder.getTasks()) {
System.out.printf(" %-28s %s%n", task.getName(), task.getCost());
}
System.out.println("----------------------------------------");
System.out.println("Total : " + repairOrder.getTotal());
System.out.println("----------------------------------------");
System.out.println("Diagnostic Report:");
System.out.println(" " + repairOrder.getDiagnosticReport());
System.out.println("========================================");
}
}

View File

@@ -0,0 +1,105 @@
package controller;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import integration.BikeRegistry;
import integration.RepairTaskCatalog;
import model.Amount;
import model.BikeDTO;
import model.RepairOrder;
import model.RepairShop;
import static org.junit.jupiter.api.Assertions.*;
class ControllerTest {
private Controller controller;
@BeforeEach
void setUp() {
BikeRegistry bikeRegistry = new BikeRegistry();
RepairTaskCatalog taskCatalog = new RepairTaskCatalog();
RepairShop repairShop = new RepairShop();
controller = new Controller(repairShop, bikeRegistry, taskCatalog);
controller.startNewRepair();
}
@Test
void enterBikeIdWithValidIdReturnsNonNullBikeDTO() {
BikeDTO bike = controller.enterBikeID("BIKE-001");
assertNotNull(bike);
}
@Test
void enterBikeIdWithValidIdReturnsCorrectBikeId() {
BikeDTO bike = controller.enterBikeID("BIKE-001");
assertEquals("BIKE-001", bike.getBikeID());
}
@Test
void enterBikeIdWithUnknownIdReturnsNull() {
BikeDTO bike = controller.enterBikeID("BIKE-999");
assertNull(bike);
}
@Test
void addRepairTaskWithValidNameReturnsNonNullAmount() {
controller.enterBikeID("BIKE-001");
Amount total = controller.addRepairTask("Brake Pad Replacement");
assertNotNull(total);
}
@Test
void addRepairTaskWithValidNameReturnsCorrectRunningTotal() {
controller.enterBikeID("BIKE-001");
Amount total = controller.addRepairTask("Brake Pad Replacement");
assertEquals(350, total.getValue(), 0.001);
}
@Test
void addTwoRepairTasksReturnsCumulativeTotal() {
controller.enterBikeID("BIKE-001");
controller.addRepairTask("Brake Pad Replacement");
Amount total = controller.addRepairTask("Tire Replacement");
assertEquals(850, total.getValue(), 0.001);
}
@Test
void addRepairTaskWithUnknownNameReturnsNull() {
controller.enterBikeID("BIKE-001");
Amount total = controller.addRepairTask("Non-existing Task");
assertNull(total);
}
@Test
void endRepairReturnsNonNullRepairOrder() {
controller.enterBikeID("BIKE-001");
controller.addRepairTask("Battery Check");
RepairOrder repairOrder = controller.endRepair();
assertNotNull(repairOrder);
}
@Test
void endRepairReturnsRepairOrderWithCorrectBikeId() {
controller.enterBikeID("BIKE-002");
RepairOrder repairOrder = controller.endRepair();
assertEquals("BIKE-002", repairOrder.getBike().getBikeID());
}
@Test
void endRepairReturnsRepairOrderWithCorrectTotalAfterTasks() {
controller.enterBikeID("BIKE-001");
controller.addRepairTask("Battery Check");
controller.addRepairTask("Chain Lubrication");
RepairOrder repairOrder = controller.endRepair();
assertEquals(350, repairOrder.getTotal().getValue(), 0.001);
}
@Test
void enterDiagnosticReportIsReflectedInFinalRepairOrder() {
controller.enterBikeID("BIKE-003");
controller.enterDiagnosticReport("Chain replaced and tested.");
RepairOrder repairOrder = controller.endRepair();
assertEquals("Chain replaced and tested.", repairOrder.getDiagnosticReport());
}
}

View File

@@ -0,0 +1,54 @@
package integration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import model.BikeDTO;
import static org.junit.jupiter.api.Assertions.*;
class BikeRegistryTest {
private BikeRegistry bikeRegistry;
@BeforeEach
void setUp() {
bikeRegistry = new BikeRegistry();
}
@Test
void findBikeWithExistingIdReturnsBikeDTO() {
BikeDTO bike = bikeRegistry.findBike("BIKE-001");
assertNotNull(bike);
}
@Test
void findBikeWithExistingIdReturnsCorrectBikeId() {
BikeDTO bike = bikeRegistry.findBike("BIKE-001");
assertEquals("BIKE-001", bike.getBikeID());
}
@Test
void findBikeWithExistingIdReturnsCorrectOwnerName() {
BikeDTO bike = bikeRegistry.findBike("BIKE-002");
assertEquals("Bob Lindqvist", bike.getOwnerName());
}
@Test
void findBikeWithNonExistingIdReturnsNull() {
BikeDTO bike = bikeRegistry.findBike("BIKE-999");
assertNull(bike);
}
@Test
void findBikeWithEmptyStringReturnsNull() {
BikeDTO bike = bikeRegistry.findBike("");
assertNull(bike);
}
@Test
void findBikeWithAllThreeSampleBikesReturnsNonNull() {
assertNotNull(bikeRegistry.findBike("BIKE-001"));
assertNotNull(bikeRegistry.findBike("BIKE-002"));
assertNotNull(bikeRegistry.findBike("BIKE-003"));
}
}

View File

@@ -0,0 +1,55 @@
package integration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import model.TaskDTO;
import static org.junit.jupiter.api.Assertions.*;
class RepairTaskCatalogTest {
private RepairTaskCatalog catalog;
@BeforeEach
void setUp() {
catalog = new RepairTaskCatalog();
}
@Test
void findTaskWithExistingNameReturnsTaskDTO() {
TaskDTO task = catalog.findTask("Brake Pad Replacement");
assertNotNull(task);
}
@Test
void findTaskWithExistingNameReturnsCorrectName() {
TaskDTO task = catalog.findTask("Tire Replacement");
assertEquals("Tire Replacement", task.getName());
}
@Test
void findTaskWithExistingNameReturnsCorrectCost() {
TaskDTO task = catalog.findTask("Battery Check");
assertEquals(200.0, task.getCost().getValue(), 0.001);
}
@Test
void findTaskWithNonExistingNameReturnsNull() {
TaskDTO task = catalog.findTask("Non-existing Task");
assertNull(task);
}
@Test
void findTaskWithEmptyStringReturnsNull() {
TaskDTO task = catalog.findTask("");
assertNull(task);
}
@Test
void findTaskWithAllFourSampleTasksReturnsNonNull() {
assertNotNull(catalog.findTask("Brake Pad Replacement"));
assertNotNull(catalog.findTask("Tire Replacement"));
assertNotNull(catalog.findTask("Battery Check"));
assertNotNull(catalog.findTask("Chain Lubrication"));
}
}

View File

@@ -0,0 +1,72 @@
package model;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class ActiveRepairTest {
private ActiveRepair activeRepair;
@BeforeEach
void setUp() {
activeRepair = new ActiveRepair();
}
@Test
void addSingleTaskReturnsTaskCostAsRunningTotal() {
TaskDTO task = new TaskDTO("Brake Pad Replacement", new Amount(350));
Amount runningTotal = activeRepair.addTask(task);
assertEquals(350, runningTotal.getValue(), 0.001);
}
@Test
void addTwoTasksReturnsCorrectCumulativeTotal() {
activeRepair.addTask(new TaskDTO("Brake Pad Replacement", new Amount(350)));
Amount runningTotal = activeRepair.addTask(new TaskDTO("Tire Replacement", new Amount(500)));
assertEquals(850, runningTotal.getValue(), 0.001);
}
@Test
void endRepairWithRegisteredBikeReturnsBikeInRepairOrder() {
BikeDTO bike = new BikeDTO("BIKE-001", "Alice Svensson");
activeRepair.registerBike(bike);
RepairOrder repairOrder = activeRepair.endRepair();
assertEquals("BIKE-001", repairOrder.getBike().getBikeID());
}
@Test
void endRepairAfterAddingTasksReturnsAllTasksInOrder() {
activeRepair.registerBike(new BikeDTO("BIKE-001", "Alice Svensson"));
activeRepair.addTask(new TaskDTO("Brake Pad Replacement", new Amount(350)));
activeRepair.addTask(new TaskDTO("Tire Replacement", new Amount(500)));
RepairOrder repairOrder = activeRepair.endRepair();
assertEquals(2, repairOrder.getTasks().size());
}
@Test
void endRepairReturnsCorrectTotalInRepairOrder() {
activeRepair.registerBike(new BikeDTO("BIKE-001", "Alice Svensson"));
activeRepair.addTask(new TaskDTO("Brake Pad Replacement", new Amount(350)));
activeRepair.addTask(new TaskDTO("Tire Replacement", new Amount(500)));
RepairOrder repairOrder = activeRepair.endRepair();
assertEquals(850, repairOrder.getTotal().getValue(), 0.001);
}
@Test
void endRepairWithoutTasksReturnsTotalOfZero() {
activeRepair.registerBike(new BikeDTO("BIKE-001", "Alice Svensson"));
RepairOrder repairOrder = activeRepair.endRepair();
assertEquals(0, repairOrder.getTotal().getValue(), 0.001);
}
@Test
void enterDiagnosticReportIsIncludedInRepairOrder() {
activeRepair.registerBike(new BikeDTO("BIKE-001", "Alice Svensson"));
String report = "Front tire replaced.";
activeRepair.enterDiagnosticReport(report);
RepairOrder repairOrder = activeRepair.endRepair();
assertEquals(report, repairOrder.getDiagnosticReport());
}
}

View File

@@ -0,0 +1,61 @@
package model;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class AmountTest {
@Test
void addTwoPositiveAmountsReturnsCorrectSum() {
Amount a = new Amount(200);
Amount b = new Amount(150);
Amount result = a.add(b);
assertEquals(350, result.getValue(), 0.001);
}
@Test
void addZeroToAmountReturnsUnchangedValue() {
Amount a = new Amount(500);
Amount zero = new Amount(0);
Amount result = a.add(zero);
assertEquals(500, result.getValue(), 0.001);
}
@Test
void addTwoDecimalAmountsReturnsCorrectSum() {
Amount a = new Amount(99.99);
Amount b = new Amount(0.01);
Amount result = a.add(b);
assertEquals(100.0, result.getValue(), 0.001);
}
@Test
void subtractSmallerAmountReturnsPositiveDifference() {
Amount a = new Amount(300);
Amount b = new Amount(100);
Amount result = a.subtract(b);
assertEquals(200, result.getValue(), 0.001);
}
@Test
void subtractEqualAmountReturnsZero() {
Amount a = new Amount(250);
Amount b = new Amount(250);
Amount result = a.subtract(b);
assertEquals(0, result.getValue(), 0.001);
}
@Test
void getValueReturnsStoredValue() {
Amount a = new Amount(123.45);
assertEquals(123.45, a.getValue(), 0.001);
}
@Test
void addIsNotMutatingOriginalAmount() {
Amount original = new Amount(100);
original.add(new Amount(50));
assertEquals(100, original.getValue(), 0.001);
}
}

View File

@@ -0,0 +1,67 @@
package model;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class RepairShopTest {
private RepairShop repairShop;
@BeforeEach
void setUp() {
repairShop = new RepairShop();
repairShop.startRepair();
}
@Test
void addTaskAfterStartReturnsTaskCostAsRunningTotal() {
TaskDTO task = new TaskDTO("Brake Pad Replacement", new Amount(350));
Amount runningTotal = repairShop.addTask(task);
assertEquals(350, runningTotal.getValue(), 0.001);
}
@Test
void addTwoTasksReturnsCumulativeTotal() {
repairShop.addTask(new TaskDTO("Brake Pad Replacement", new Amount(350)));
Amount runningTotal = repairShop.addTask(new TaskDTO("Tire Replacement", new Amount(500)));
assertEquals(850, runningTotal.getValue(), 0.001);
}
@Test
void endRepairAfterRegisterBikeAndTasksReturnsRepairOrderWithBike() {
BikeDTO bike = new BikeDTO("BIKE-002", "Bob Lindqvist");
repairShop.registerBike(bike);
repairShop.addTask(new TaskDTO("Battery Check", new Amount(200)));
RepairOrder repairOrder = repairShop.endRepair();
assertEquals("BIKE-002", repairOrder.getBike().getBikeID());
}
@Test
void endRepairReturnsRepairOrderWithCorrectTotal() {
repairShop.registerBike(new BikeDTO("BIKE-002", "Bob Lindqvist"));
repairShop.addTask(new TaskDTO("Battery Check", new Amount(200)));
repairShop.addTask(new TaskDTO("Chain Lubrication", new Amount(150)));
RepairOrder repairOrder = repairShop.endRepair();
assertEquals(350, repairOrder.getTotal().getValue(), 0.001);
}
@Test
void startRepairTwiceCreatesNewSessionWithZeroTotal() {
repairShop.registerBike(new BikeDTO("BIKE-001", "Alice Svensson"));
repairShop.addTask(new TaskDTO("Brake Pad Replacement", new Amount(350)));
repairShop.startRepair();
repairShop.registerBike(new BikeDTO("BIKE-002", "Bob Lindqvist"));
RepairOrder repairOrder = repairShop.endRepair();
assertEquals(0, repairOrder.getTotal().getValue(), 0.001);
}
@Test
void enterDiagnosticReportIsReflectedInRepairOrder() {
repairShop.registerBike(new BikeDTO("BIKE-003", "Carl Johansson"));
repairShop.enterDiagnosticReport("Tire replaced successfully.");
RepairOrder repairOrder = repairShop.endRepair();
assertEquals("Tire replaced successfully.", repairOrder.getDiagnosticReport());
}
}