Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<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>com.ramiro</groupId>
<artifactId>exception-ready-people-registry</artifactId>
<version>1.0.0</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.jupiter.version>5.11.0</junit.jupiter.version>
</properties>

<dependencies>
<!-- JUnit 5 (solo para test) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<!-- Compila a Java 17 -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
</plugin>

<!-- Ejecuta los tests JUnit 5 -->
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
</plugins>
</build>
</project>
33 changes: 33 additions & 0 deletions src/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Exception-Ready People Registry

A concise Java 17 solution for the Ironhack Exceptions lab. It showcases clean exception handling, strict input validation, safe object cloning, and simple file I/O—fully covered by JUnit 5 tests. Minimal surface area, fast to read, easy to run, ready for review.

WHAT THIS PROJECT DELIVERS
• Person: id, name (“firstName lastName”), age, occupation. Validates non-negative age. Equality intentionally ignores id as required by the lab.
• PersonsList: in-memory registry with three core capabilities:
– findByName(String): exact match; validates the “firstName lastName” format; throws IllegalArgumentException on bad format and NoSuchElementException when not found.
– clone(Person): creates a new Person with the same properties and a new id.
– writePersonToFile(Person, path): writes Person.toString() using try-with-resources; handles I/O failures gracefully.
• Tests (JUnit 5): verify negative-age rejection, successful name lookup, invalid name format, “not found” behavior, and cloning with a new id.

PROJECT STRUCTURE (Maven standard)
src/main/java/com/ramiro/exceptionslab/Person.java
src/main/java/com/ramiro/exceptionslab/PersonsList.java
src/test/java/com/ramiro/exceptionslab/PersonLabTests.java
pom.xml (Java 17, JUnit 5, Surefire)

HOW TO RUN
• From project root: mvn test
• Run a specific class: mvn -Dtest=com.ramiro.exceptionslab.PersonLabTests test
• In IntelliJ IDEA: open the project, right-click PersonLabTests, Run.

WHY THIS MATTERS
• Clear, enforceable validation at construction and setters.
• Explicit, meaningful exceptions instead of silent failures.
• Deterministic cloning and file output that are easy to reason about and to test.
• Clean, reviewer-friendly code: small classes, zero unnecessary dependencies.

CONFIG NOTES
• Requires Java 17.
• JUnit 5 is test-scope only; production code has no runtime third-party dependencies.
• File writing uses the platform default charset; adjust if your environment requires a specific encoding.
58 changes: 58 additions & 0 deletions src/main/java/com/ramiro/exceptionslab/Person.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.ramiro.exceptionslab;

import java.util.Objects;

public class Person {
private final int id;
private String name; // "firstName lastName"
private int age; // must be >= 0
private String occupation;

public Person(int id, String name, int age, String occupation) {
this.id = id;
this.name = Objects.requireNonNull(name, "name");
setAge(age); // validates >= 0
this.occupation = Objects.requireNonNull(occupation, "occupation");
}

public int getId() { return id; }
public String getName() { return name; }
public int getAge() { return age; }
public String getOccupation() { return occupation; }

public void setAge(int age) {
if (age < 0) throw new IllegalArgumentException("Age must be >= 0");
this.age = age;
}

/** Lab requirement: equals(Person) that ignores id */
public boolean equals(Person other) {
if (other == null) return false;
return Objects.equals(this.name, other.name)
&& this.age == other.age
&& Objects.equals(this.occupation, other.occupation);
}

/** Proper Object.equals override delegating to equals(Person) */
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person p)) return false;
return equals(p);
}

@Override
public int hashCode() {
// ignore id to be consistent with equals
return Objects.hash(name, age, occupation);
}

@Override
public String toString() {
return "Person{id=" + id +
", name='" + name + '\'' +
", age=" + age +
", occupation='" + occupation + '\'' +
'}';
}
}
63 changes: 63 additions & 0 deletions src/main/java/com/ramiro/exceptionslab/PersonsList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.ramiro.exceptionslab;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

public class PersonsList {
private final List<Person> people = new ArrayList<>();

public void add(Person p) {
people.add(Objects.requireNonNull(p));
}

/** Exact match; throws if name is not "firstName lastName" */
public Person findByName(String name) {
String validated = validateFullName(name); // may throw IllegalArgumentException
for (Person p : people) {
if (p.getName().equals(validated)) return p;
}
throw new NoSuchElementException("No person found with name: " + validated);
}

/** Returns a new Person with same props, but a new id */
public Person clone(Person original) {
Objects.requireNonNull(original, "original");
int newId = nextId();
return new Person(newId, original.getName(), original.getAge(), original.getOccupation());
}

/** Writes Person.toString() to file; handles IO errors internally and returns success flag */
public boolean writePersonToFile(Person p, String filePath) {
Objects.requireNonNull(p, "person");
Objects.requireNonNull(filePath, "filePath");
try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath, false))) {
bw.write(p.toString());
bw.newLine();
return true;
} catch (IOException e) {
System.err.println("Failed to write person to file: " + e.getMessage());
return false;
}
}

// --- helpers ---
private String validateFullName(String name) {
if (name == null) throw new IllegalArgumentException("Name cannot be null");
String trimmed = name.trim();
String[] parts = trimmed.split("\\s+");
if (parts.length != 2) {
throw new IllegalArgumentException("Name must be formatted as 'firstName lastName'");
}
return parts[0] + " " + parts[1];
}

private int nextId() {
int max = 0;
for (Person p : people) max = Math.max(max, p.getId());
return max + 1;
}

public List<Person> getAll() { return Collections.unmodifiableList(people); }
}
58 changes: 58 additions & 0 deletions src/test/java/com/ramiro/exceptionslab/PersonLabTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.ramiro.exceptionslab;

import org.junit.jupiter.api.Test;

import java.util.NoSuchElementException;

import static org.junit.jupiter.api.Assertions.*;

class PersonLabTests {

@Test
void setAge_throws_whenNegative() {
Person p = new Person(1, "John Doe", 20, "Engineer");
assertThrows(IllegalArgumentException.class, () -> p.setAge(-1));
}

@Test
void findByName_returnsCorrectPerson_whenProperlyFormatted() {
PersonsList list = new PersonsList();
Person a = new Person(1, "Alice Smith", 30, "Designer");
Person b = new Person(2, "Bob Jones", 25, "Developer");
list.add(a); list.add(b);

Person found = list.findByName("Bob Jones");
assertTrue(found.equals(b)); // equals(Person) ignoring id
assertEquals(b, found); // equals(Object) also works
}

@Test
void findByName_throws_whenBadFormat() {
PersonsList list = new PersonsList();
list.add(new Person(1, "Alice Smith", 30, "Designer"));

assertThrows(IllegalArgumentException.class, () -> list.findByName("Alice"));
assertThrows(IllegalArgumentException.class, () -> list.findByName(" Alice "));
assertThrows(IllegalArgumentException.class, () -> list.findByName("Alice B C"));
assertThrows(IllegalArgumentException.class, () -> list.findByName(null));
}

@Test
void findByName_throws_whenNotFound() {
PersonsList list = new PersonsList();
list.add(new Person(1, "Alice Smith", 30, "Designer"));

assertThrows(NoSuchElementException.class, () -> list.findByName("Bob Jones"));
}

@Test
void clone_createsNewId_andSameProperties() {
PersonsList list = new PersonsList();
Person a = new Person(7, "Cara White", 40, "Teacher");
list.add(a);

Person c = list.clone(a);
assertNotEquals(a.getId(), c.getId(), "clone must have a new id");
assertTrue(c.equals(a), "clone must match all properties except id");
}
}