diff --git a/src/main/java/MakeItFit/utils/EmailValidator.java b/src/main/java/MakeItFit/utils/EmailValidator.java index 4980f9a..5acabcf 100644 --- a/src/main/java/MakeItFit/utils/EmailValidator.java +++ b/src/main/java/MakeItFit/utils/EmailValidator.java @@ -1,6 +1,5 @@ package MakeItFit.utils; -import java.io.Serializable; import java.util.regex.Pattern; /** @@ -11,7 +10,11 @@ */ public class EmailValidator { + /* fails several tests private static final String EMAIL_PATTERN = "^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"; + */ + private static final String EMAIL_PATTERN = + "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"; /** * Verifies if the email is valid. diff --git a/src/main/java/MakeItFit/utils/MyTuple.java b/src/main/java/MakeItFit/utils/MyTuple.java index 12b3ceb..f18b6fb 100644 --- a/src/main/java/MakeItFit/utils/MyTuple.java +++ b/src/main/java/MakeItFit/utils/MyTuple.java @@ -11,7 +11,10 @@ * @author Afonso Santos (a104276), Hélder Gomes (a104100) and Pedro Pereira (a104082) * @version (11052024) */ +/* References to generic type MyTuple should be parameterized public class MyTuple implements Serializable, Comparable { +*/ +public class MyTuple implements Serializable, Comparable> { private final T1 item1; private final T2 item2; @@ -81,7 +84,10 @@ public boolean equals(Object o) { * or greater than the other tuple */ @Override + /* References to generic type MyTuple should be parameterized public int compareTo(MyTuple other) { + */ + public int compareTo(MyTuple other) { int compareItem1 = this.item1.toString().compareTo(other.item1.toString()); if (compareItem1 == 0) { return this.item2.toString().compareTo(other.item2.toString()); @@ -95,7 +101,11 @@ public int compareTo(MyTuple other) { * @return A new MyTuple instance that is a copy of the current instance. */ @Override + /* References to generic type MyTuple should be parameterized public MyTuple clone() { return new MyTuple(this.item1, this.item2); + */ + public MyTuple clone() { + return new MyTuple(this.item1, this.item2); } } diff --git a/src/unittests/java/MakeItFit/utils/EmailValidatorTest.java b/src/unittests/java/MakeItFit/utils/EmailValidatorTest.java new file mode 100644 index 0000000..879c23e --- /dev/null +++ b/src/unittests/java/MakeItFit/utils/EmailValidatorTest.java @@ -0,0 +1,93 @@ +package MakeItFit.utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class EmailValidatorTest { + @Test + void testQuotedAndDoubleDot() { + assertTrue(EmailValidator.isValidEmail("\"john..doe\"@uminho.pt")); + } + + @Test + void testIPv4LiteralDomain() { + assertTrue(EmailValidator.isValidEmail("user@[192.168.0.1]")); + } + + @Test + void testLocalBangAndPercent() { + assertTrue(EmailValidator.isValidEmail("user%example.com@example.org")); + } + + @Test + void testSingleLetters() { + assertTrue(EmailValidator.isValidEmail("x@y.co")); + } + + @Test + void testLocalQuotedSingleLetter() { + assertTrue(EmailValidator.isValidEmail("\"a\"@b.co")); + } + + @Test + void testLocalPlusTag() { + assertTrue(EmailValidator.isValidEmail("first.last+tag@example.com")); + } + + @Test + void testLocalAndDomainHyphenOrUnderscore() { + assertTrue(EmailValidator.isValidEmail("first_last-123@sub-domain.example.co.uk")); + } + + @Test + void testDomainStartsWithHyphen() { + assertFalse(EmailValidator.isValidEmail("user@-example.com")); + } + + @Test + void testDomainEndsWithHyphen() { + assertFalse(EmailValidator.isValidEmail("user@example-.com")); + } + + @Test + void testDomainConsecutiveDots() { + assertFalse(EmailValidator.isValidEmail("user@sub..example.com")); + } + + @Test + void testLocalTrailingDot() { + assertFalse(EmailValidator.isValidEmail("user.@example.com")); + } + + @Test + void testLocalStartsWithDot() { + assertFalse(EmailValidator.isValidEmail(".user@example.com")); + } + + @Test + void testDomainSpace() { + assertFalse(EmailValidator.isValidEmail("user@exa mple.com")); + } + + @Test + void testTLDMissing() { + assertFalse(EmailValidator.isValidEmail("user@example")); + } + + @Test + void testQuotedAndSpace() { + assertFalse(EmailValidator.isValidEmail("\"john doe\"@uminho.pt")); + } + + @Test + void testEmpty() { + assertFalse(EmailValidator.isValidEmail("")); + } + + @Test + void testToForceCoverage() { + new EmailValidator(); + } +} diff --git a/src/unittests/java/MakeItFit/utils/ExtendedRandomTest.java b/src/unittests/java/MakeItFit/utils/ExtendedRandomTest.java new file mode 100644 index 0000000..8d5f772 --- /dev/null +++ b/src/unittests/java/MakeItFit/utils/ExtendedRandomTest.java @@ -0,0 +1,65 @@ +package MakeItFit.utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +public class ExtendedRandomTest { + private int SAMPLE_SIZE = 1000; + + @Test + void testRangeBoundariesUnseededRandom() { + ExtendedRandom unseededRandom = new ExtendedRandom(); + for (int i = 0; i < SAMPLE_SIZE; i++) { + int expected = unseededRandom.nextInt(5, 15); + assertTrue(expected >= 5); + assertTrue(expected < 15); + } + } + + @Test + void testDeterministicOutputSeededRandom() { + ExtendedRandom seededRandom = new ExtendedRandom(123456L); + int[] firstRun = new int[5]; + for (int i = 0; i < firstRun.length; i++) { + firstRun[i] = seededRandom.nextInt(5, 10); + } + + ExtendedRandom repeatRandom = new ExtendedRandom(123456L); + for (int i = 0; i < firstRun.length; i++) { + assertEquals(firstRun[i], repeatRandom.nextInt(5, 10)); + } + } + + @Test + void testOriginEqualThrows() { + ExtendedRandom unseededRandom = new ExtendedRandom(); + assertThrows(IllegalArgumentException.class, () -> unseededRandom.nextInt(10, 10)); + } + + @Test + void testOriginGreaterThrows() { + ExtendedRandom unseededRandom = new ExtendedRandom(); + assertThrows(IllegalArgumentException.class, () -> unseededRandom.nextInt(15, 5)); + } + + @Test + void testSingleValueRange() { + ExtendedRandom unseededRandom = new ExtendedRandom(); + for (int i = 0; i < SAMPLE_SIZE; i++) { + assertEquals(5, unseededRandom.nextInt(5, 6)); + } + } + + @Test + void testNegativeOriginPositiveBound() { + ExtendedRandom unseededRandom = new ExtendedRandom(); + for (int i = 0; i < SAMPLE_SIZE; i++) { + int expected = unseededRandom.nextInt(-5, 5); + assertTrue(expected >= -5); + assertTrue(expected < 5); + } + } +} diff --git a/src/unittests/java/MakeItFit/utils/MakeItFitDateTest.java b/src/unittests/java/MakeItFit/utils/MakeItFitDateTest.java new file mode 100644 index 0000000..5a5eed2 --- /dev/null +++ b/src/unittests/java/MakeItFit/utils/MakeItFitDateTest.java @@ -0,0 +1,201 @@ +package MakeItFit.utils; + +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +public class MakeItFitDateTest { + @Test + void testConstructor() { + MakeItFitDate currentDate = new MakeItFitDate(); + assertTrue(LocalDate.now().isBefore(currentDate.getDate()) || + LocalDate.now().isEqual(currentDate.getDate())); + } + + @Test + void testFromStringValidStandardFormat() { + MakeItFitDate date = MakeItFitDate.fromString("04/06/2025"); + assertEquals(4, date.getDayOfMonth()); + assertEquals(6, date.getMonth()); + assertEquals(2025, date.getYear()); + assertEquals(3, date.getDayOfWeek()); + } + + @Test + void testFromStringValidBoundary() { + MakeItFitDate date = MakeItFitDate.fromString("31/12/1999"); + assertEquals(31, date.getDayOfMonth()); + assertEquals(12, date.getMonth()); + assertEquals(1999, date.getYear()); + } + + @Test + void testFromStringInvalidDelimiter() { + assertThrows(IllegalArgumentException.class, () -> MakeItFitDate.fromString("04-06-2025")); + } + + @Test + void testFromStringInvalidPartsCount() { + assertThrows(IllegalArgumentException.class, () -> MakeItFitDate.fromString("01/01")); + } + + @Test + void testFromStringInvalidNonNumeric() { + assertThrows(IllegalArgumentException.class, () -> MakeItFitDate.fromString("aa/bb/cccc")); + } + + @Test + void testFromStringInvalidEmptyString() { + assertThrows(IllegalArgumentException.class, () -> MakeItFitDate.fromString("")); + } + + @Test + void testsFromStringInvalidNullString() { + assertThrows(NullPointerException.class, () -> MakeItFitDate.fromString(null)); + } + + @Test + void testsToStringFormat() { + assertEquals("04/06/2025", MakeItFitDate.of(2025, 6, 4).toString()); + } + + @Test + void testCrossMonthBoundary() { + assertEquals("02/02/2021", MakeItFitDate.fromString("28/01/2021").plusDays(5).toString()); + } + + @Test + void testCompareToOrdering() { + assertTrue(MakeItFitDate.fromString("01/01/2025") + .compareTo(MakeItFitDate.fromString("15/06/2025")) < 0); + assertTrue(MakeItFitDate.fromString("15/06/2025") + .compareTo(MakeItFitDate.fromString("01/01/2025")) > 0); + } + + @Test + void testIsBefore() { + assertTrue(MakeItFitDate.fromString("01/01/2025") + .isBefore(MakeItFitDate.fromString("15/06/2025"))); + } + + @Test + void testIsBefore2() { + assertFalse(MakeItFitDate.fromString("15/06/2025") + .isBefore(MakeItFitDate.fromString("01/01/2025"))); + } + + @Test + void testIsBefore3() { + assertFalse(MakeItFitDate.fromString("01/01/2025") + .isBefore(MakeItFitDate.fromString("01/01/2025"))); + } + + @Test + void testIsBeforeOrSame() { + assertTrue(MakeItFitDate.fromString("01/01/2025") + .isBeforeOrSame(MakeItFitDate.fromString("15/06/2025"))); + } + + @Test + void testIsBeforeOrSame2() { + assertFalse(MakeItFitDate.fromString("15/06/2025") + .isBeforeOrSame(MakeItFitDate.fromString("01/01/2025"))); + } + + @Test + void testIsBeforeOrSame3() { + assertTrue(MakeItFitDate.fromString("01/01/2025") + .isBeforeOrSame(MakeItFitDate.fromString("01/01/2025"))); + } + + @Test + void testIsAfter() { + assertFalse( + MakeItFitDate.fromString("01/01/2025").isAfter(MakeItFitDate.fromString("15/06/2025"))); + } + + @Test + void testIsAfter2() { + assertTrue( + MakeItFitDate.fromString("15/06/2025").isAfter(MakeItFitDate.fromString("01/01/2025"))); + } + + @Test + void testIsAfter3() { + assertFalse( + MakeItFitDate.fromString("01/01/2025").isAfter(MakeItFitDate.fromString("01/01/2025"))); + } + + @Test + void testIsAfterOrSame() { + assertFalse(MakeItFitDate.fromString("01/01/2025") + .isAfterOrSame(MakeItFitDate.fromString("15/06/2025"))); + } + + @Test + void testIsAfterOrSame2() { + assertTrue(MakeItFitDate.fromString("15/06/2025") + .isAfterOrSame(MakeItFitDate.fromString("01/01/2025"))); + } + + @Test + void testIsAfterOrSame3() { + assertTrue(MakeItFitDate.fromString("01/01/2025") + .isAfterOrSame(MakeItFitDate.fromString("01/01/2025"))); + } + + @Test + void testDistanceReturnsZero() { + assertEquals(0, + MakeItFitDate.fromString("04/06/2025") + .distance(MakeItFitDate.fromString("04/06/2025"))); + } + + @Test + void testDistanceAdjacentDays() { + assertEquals(1, + MakeItFitDate.fromString("10/10/2025") + .distance(MakeItFitDate.fromString("11/10/2025"))); + } + + @Test + void testDistanceAcrossMonths() { + assertEquals(5, + MakeItFitDate.fromString("28/01/2025") + .distance(MakeItFitDate.fromString("02/02/2025"))); + } + + @Test + void testDistanceAcrossYears() { + assertEquals(7305, + MakeItFitDate.fromString("01/01/2000") + .distance(MakeItFitDate.fromString("01/01/2020"))); + } + + @Test + void testEqualsTrue() { + assertTrue( + MakeItFitDate.fromString("15/05/2025").equals(MakeItFitDate.fromString("15/05/2025"))); + } + + @Test + void testEqualsFalse() { + assertFalse( + MakeItFitDate.fromString("15/05/2015").equals(MakeItFitDate.fromString("16/05/2015"))); + } + + @Test + void testClone() { + MakeItFitDate date = MakeItFitDate.of(2025, 06, 04); + MakeItFitDate dateClone = date.clone(); + + assertTrue(dateClone.equals(date)); + assertNotSame(dateClone, date); + } +} diff --git a/src/unittests/java/MakeItFit/utils/MyTupleTest.java b/src/unittests/java/MakeItFit/utils/MyTupleTest.java new file mode 100644 index 0000000..3d57977 --- /dev/null +++ b/src/unittests/java/MakeItFit/utils/MyTupleTest.java @@ -0,0 +1,95 @@ +package MakeItFit.utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class MyTupleTest { + @Test + void testConstructor() { + MyTuple tuple = new MyTuple<>("hello", "world"); + assertEquals("hello", tuple.getItem1()); + assertEquals("world", tuple.getItem2()); + } + + @Test + void tesConstructorNullParameters() { + MyTuple tuple = new MyTuple<>(null, null); + assertNull(tuple.getItem1()); + assertNull(tuple.getItem2()); + } + + @Test + void testToStringFormat() { + MyTuple tuple = new MyTuple<>("A", 24); + assertEquals("(A, 24)", tuple.toString()); + } + + @Test + void testEqualsItem1Differs() { + MyTuple tuple1 = new MyTuple<>("A", 24); + MyTuple tuple2 = new MyTuple<>("B", 24); + assertFalse(tuple1.equals(tuple2)); + } + + @Test + void testEqualsItem2Differs() { + MyTuple tuple1 = new MyTuple<>("A", 24); + MyTuple tuple2 = new MyTuple<>("A", 25); + assertFalse(tuple1.equals(tuple2)); + } + + @Test + void testEquals() { + MyTuple tuple = new MyTuple<>("A", "24"); + assertTrue(tuple.equals(tuple)); + } + + @Test + void testEqualsNullParameter() { + MyTuple tuple = new MyTuple<>(24, "A"); + assertFalse(tuple.equals(null)); + } + + @Test + @SuppressWarnings("unlikely-arg-type") + void testEqualsDifferentClass() { + MyTuple tuple = new MyTuple<>("A", 24); + assertFalse(tuple.equals("(A, 24)")); + } + + @Test + void testCompareToItem1Different() { + MyTuple tuple1 = new MyTuple<>("A", 24); + MyTuple tuple2 = new MyTuple<>("B", 24); + assertTrue(tuple1.compareTo(tuple2) < 0); + assertTrue(tuple2.compareTo(tuple1) > 0); + } + + @Test + void testCompareToItem2Different() { + MyTuple tuple1 = new MyTuple<>("A", 24); + MyTuple tuple2 = new MyTuple<>("A", 25); + assertTrue(tuple1.compareTo(tuple2) < 0); + assertTrue(tuple2.compareTo(tuple1) > 0); + } + + @Test + void testCompareToEqualTuples() { + MyTuple tuple1 = new MyTuple<>("A", 24); + MyTuple tuple2 = new MyTuple<>("A", 24); + assertTrue(tuple1.compareTo(tuple2) == 0); + } + + @Test + void testClone() { + MyTuple tuple = new MyTuple<>("A", 24); + MyTuple tupleClone = tuple.clone(); + assertEquals(tuple, tupleClone); + assertNotSame(tuple, tupleClone); + } +}