From 13caa3fc8e44f4eecc5b9ea2be655b90edfe309c Mon Sep 17 00:00:00 2001 From: Miguel Reboiro-Jato Date: Fri, 23 Oct 2015 18:21:43 +0200 Subject: [PATCH] Adds the administrator entity The "administrator" entity has been added to represent the administrators of the application. --- .../xcs/domain/entities/Administrator.java | 37 +++++ .../uvigo/esei/xcs/domain/entities/Owner.java | 111 ++----------- .../uvigo/esei/xcs/domain/entities/Pet.java | 19 ++- .../uvigo/esei/xcs/domain/entities/User.java | 135 ++++++++++++++++ .../domain/entities/AdministratorTest.java | 8 + .../domain/entities/EntitiesTestSuite.java | 5 +- .../esei/xcs/domain/entities/OwnerTest.java | 136 +--------------- .../esei/xcs/domain/entities/UserTest.java | 150 ++++++++++++++++++ .../xcs/domain/entities/IsEqualsToEntity.java | 56 +++++++ .../xcs/domain/entities/IsEqualsToOwner.java | 65 ++++++++ .../xcs/domain/entities/IsEqualsToPet.java | 68 ++++++++ .../xcs/domain/entities/OwnersDataset.java | 88 ++++++++++ 12 files changed, 640 insertions(+), 238 deletions(-) create mode 100644 domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Administrator.java create mode 100644 domain/src/main/java/es/uvigo/esei/xcs/domain/entities/User.java create mode 100644 domain/src/test/java/es/uvigo/esei/xcs/domain/entities/AdministratorTest.java create mode 100644 domain/src/test/java/es/uvigo/esei/xcs/domain/entities/UserTest.java create mode 100644 service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToEntity.java create mode 100644 service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToOwner.java create mode 100644 service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToPet.java create mode 100644 service/src/test/java/es/uvigo/esei/xcs/domain/entities/OwnersDataset.java diff --git a/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Administrator.java b/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Administrator.java new file mode 100644 index 0000000..c320166 --- /dev/null +++ b/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Administrator.java @@ -0,0 +1,37 @@ +package es.uvigo.esei.xcs.domain.entities; + +import java.io.Serializable; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; + +/** + * An administrator of the application. + * + * @author Miguel Reboiro Jato + */ +@Entity +@DiscriminatorValue("ADMIN") +public class Administrator extends User implements Serializable { + private static final long serialVersionUID = 1L; + + // Required for JPA + Administrator() {} + + /** + * Creates a new instance of {@code Administrator}. + * + * @param login the login that identifies the user. This parameter must be a + * non empty and non {@code null} string with a maximum length of 100 chars. + * @param password the raw password of the user. This parameter must be a + * non {@code null} string with a minimum length of 6 chars. + * + * @throws NullPointerException if a {@code null} value is passed as the + * value for any parameter. + * @throws IllegalArgumentException if value provided for any parameter is + * not valid according to its description. + */ + public Administrator(String login, String password) { + super(login, password); + } +} diff --git a/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Owner.java b/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Owner.java index b61ae5f..312bd79 100644 --- a/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Owner.java +++ b/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Owner.java @@ -3,21 +3,15 @@ package es.uvigo.esei.xcs.domain.entities; import static java.util.Arrays.stream; import static java.util.Collections.unmodifiableCollection; import static java.util.Objects.requireNonNull; -import static org.apache.commons.lang3.Validate.inclusiveBetween; -import static org.apache.commons.lang3.Validate.matchesPattern; import java.io.Serializable; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collection; import javax.persistence.CascadeType; -import javax.persistence.Column; +import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; -import javax.persistence.Id; import javax.persistence.OneToMany; -import javax.xml.bind.annotation.adapters.HexBinaryAdapter; /** * A pet owner. @@ -25,17 +19,16 @@ import javax.xml.bind.annotation.adapters.HexBinaryAdapter; * @author Miguel Reboiro-Jato */ @Entity -public class Owner implements Serializable { +@DiscriminatorValue("OWNER") +public class Owner extends User implements Serializable { private static final long serialVersionUID = 1L; - - @Id - @Column(length = 100, nullable = false) - private String login; - - @Column(length = 32, nullable = false) - private String password; - @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany( + mappedBy = "owner", + targetEntity = Pet.class, + cascade = CascadeType.ALL, + orphanRemoval = true + ) private Collection pets; // Required for JPA @@ -55,8 +48,7 @@ public class Owner implements Serializable { * not valid according to its description. */ public Owner(String login, String password) { - this.setLogin(login); - this.changePassword(password); + super(login, password); this.pets = new ArrayList<>(); } @@ -76,92 +68,11 @@ public class Owner implements Serializable { * not valid according to its description. */ public Owner(String login, String password, Pet ... pets) { - this.setLogin(login); - this.changePassword(password); + super(login, password); this.pets = new ArrayList<>(); stream(pets).forEach(this::addPet); } - - /** - * Returns the login of this owner. - * - * @return the login of this owner. - */ - public String getLogin() { - return login; - } - - /** - * Sets the login of this owner. - * - * @param login the login that identifies the owner. This parameter must be - * a non empty and non {@code null} string with a maximum length of 100 - * chars. - * @throws NullPointerException if {@code null} is passed as parameter. - * @throws IllegalArgumentException if the length of the string passed is - * not valid. - */ - public void setLogin(String login) { - requireNonNull(login, "login can't be null"); - inclusiveBetween(1, 100, login.length(), "login must have a length between 1 and 100"); - - this.login = login; - } - - /** - * Returns the MD5 of the owner's password. Capital letters are used in the - * returned string. - * - * @return the MD5 of the owner's password. Capital letters are used in the - * returned string. - */ - public String getPassword() { - return password; - } - - /** - * Sets the MD5 password of the owner. The MD5 string is stored with capital - * letters. - * - * @param password the MD5 password of the user. This parameter must be a - * non {@code null} MD5 string. - * @throws NullPointerException if {@code null} is passed as parameter. - * @throws IllegalArgumentException if the string passed is not a valid MD5 - * string. - */ - public void setPassword(String password) { - requireNonNull(password, "password can't be null"); - matchesPattern(password, "[a-zA-Z0-9]{32}", "password must be a valid uppercase MD5 string"); - - this.password = password.toUpperCase(); - } - - /** - * Changes the password of the owner. This method receives the raw value of - * the password and stores it in MD5 format. - * - * @param password the raw password of the user. This parameter must be a - * non {@code null} string with a minimum length of 6 chars. - * - * @throws NullPointerException if the {@code password} is {@code null}. - * @throws IllegalArgumentException if the length of the string passed is - * not valid. - */ - public void changePassword(String password) { - requireNonNull(password, "password can't be null"); - if (password.length() < 6) - throw new IllegalArgumentException("password can't be shorter than 6"); - - try { - final MessageDigest digester = MessageDigest.getInstance("MD5"); - final HexBinaryAdapter adapter = new HexBinaryAdapter(); - - this.password = adapter.marshal(digester.digest(password.getBytes())); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("MD5 algorithm not found", e); - } - } /** * Returns the pets that belongs to this owner. The collection returned is diff --git a/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Pet.java b/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Pet.java index 447fd12..1f0996c 100644 --- a/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Pet.java +++ b/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/Pet.java @@ -11,6 +11,7 @@ import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; @@ -22,12 +23,12 @@ import javax.persistence.TemporalType; * * @author Miguel Reboiro-Jato */ -@Entity +@Entity(name = "Pet") public class Pet implements Serializable { private static final long serialVersionUID = 1L; @Id - @GeneratedValue + @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column(length = 100, nullable = false) @@ -42,12 +43,18 @@ public class Pet implements Serializable { private Date birth; @ManyToOne - @JoinColumn(name = "owner") + @JoinColumn(name = "owner", referencedColumnName = "login") private Owner owner; - // Required for JPA + // Required for JPA. Pet() {} + // For testing purposes. + Pet(int id, String name, AnimalType animal, Date birth) { + this(name, animal, birth, null); + this.id = id; + } + /** * Creates a new instance of {@code Pet} without owner. * @@ -88,6 +95,10 @@ public class Pet implements Serializable { this.setBirth(birth); this.setOwner(owner); } + + public int getId() { + return id; + } /** * Returns the name of the pet. diff --git a/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/User.java b/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/User.java new file mode 100644 index 0000000..289b34a --- /dev/null +++ b/domain/src/main/java/es/uvigo/esei/xcs/domain/entities/User.java @@ -0,0 +1,135 @@ +package es.uvigo.esei.xcs.domain.entities; + +import static java.util.Objects.requireNonNull; +import static org.apache.commons.lang3.Validate.inclusiveBetween; +import static org.apache.commons.lang3.Validate.matchesPattern; + +import java.io.Serializable; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.persistence.Column; +import javax.persistence.DiscriminatorColumn; +import javax.persistence.DiscriminatorType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.xml.bind.annotation.adapters.HexBinaryAdapter; + +@Entity +@Inheritance +@DiscriminatorColumn( + name = "role", + discriminatorType = DiscriminatorType.STRING, + length = 5 +) +public abstract class User implements Serializable { + private static final long serialVersionUID = 1L; + + @Id + @Column(length = 100, nullable = false) + protected String login; + + @Column(length = 32, nullable = false) + protected String password; + + User() {} + + /** + * Creates a new instance of {@code User}. + * + * @param login the login that identifies the user. This parameter must be a + * non empty and non {@code null} string with a maximum length of 100 chars. + * @param password the raw password of the user. This parameter must be a + * non {@code null} string with a minimum length of 6 chars. + * + * @throws NullPointerException if a {@code null} value is passed as the + * value for any parameter. + * @throws IllegalArgumentException if value provided for any parameter is + * not valid according to its description. + */ + public User(String login, String password) { + this.setLogin(login); + this.changePassword(password); + } + + /** + * Returns the login of this user. + * + * @return the login of this user. + */ + public String getLogin() { + return login; + } + + /** + * Sets the login of this user. + * + * @param login the login that identifies the user. This parameter + * must be a non empty and non {@code null} string with a maximum length of + * 100 chars. + * @throws NullPointerException if {@code null} is passed as parameter. + * @throws IllegalArgumentException if the length of the string passed is + * not valid. + */ + public void setLogin(String login) { + requireNonNull(login, "login can't be null"); + inclusiveBetween(1, 100, login.length(), "login must have a length between 1 and 100"); + + this.login = login; + } + + /** + * Returns the MD5 of the user's password. Capital letters are used + * in the returned string. + * + * @return the MD5 of the user's password. Capital letters are used + * in the returned string. + */ + public String getPassword() { + return password; + } + + /** + * Sets the MD5 password of the user. The MD5 string is stored with + * capital letters. + * + * @param password the MD5 password of the user. This parameter must be a + * non {@code null} MD5 string. + * @throws NullPointerException if {@code null} is passed as parameter. + * @throws IllegalArgumentException if the string passed is not a valid MD5 + * string. + */ + public void setPassword(String password) { + requireNonNull(password, "password can't be null"); + matchesPattern(password, "[a-zA-Z0-9]{32}", "password must be a valid MD5 string"); + + this.password = password.toUpperCase(); + } + + /** + * Changes the password of the user. This method receives the rawvalue of + * the password and stores it in MD5 format. + * + * @param password the raw password of the user. This parameter must be a + * non {@code null} string with a minimum length of 6 chars. + * + * @throws NullPointerException if the {@code password} is {@code null}. + * @throws IllegalArgumentException if the length of the string passed is + * not valid. + */ + public void changePassword(String password) { + requireNonNull(password, "password can't be null"); + if (password.length() < 6) + throw new IllegalArgumentException("password can't be shorter than 6"); + + try { + final MessageDigest digester = MessageDigest.getInstance("MD5"); + final HexBinaryAdapter adapter = new HexBinaryAdapter(); + + this.password = adapter.marshal(digester.digest(password.getBytes())); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5 algorithm not found", e); + } + } +} \ No newline at end of file diff --git a/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/AdministratorTest.java b/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/AdministratorTest.java new file mode 100644 index 0000000..80c2c6a --- /dev/null +++ b/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/AdministratorTest.java @@ -0,0 +1,8 @@ +package es.uvigo.esei.xcs.domain.entities; + +public class AdministratorTest extends UserTest { + @Override + protected User newUser(String login, String password) { + return new Administrator(login, password); + } +} diff --git a/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/EntitiesTestSuite.java b/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/EntitiesTestSuite.java index 487ac44..08d5dcd 100644 --- a/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/EntitiesTestSuite.java +++ b/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/EntitiesTestSuite.java @@ -7,8 +7,7 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({ OwnerTest.class, + AdministratorTest.class, PetTest.class }) -public class EntitiesTestSuite { - -} +public class EntitiesTestSuite {} diff --git a/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/OwnerTest.java b/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/OwnerTest.java index 8cfce59..928bae2 100644 --- a/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/OwnerTest.java +++ b/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/OwnerTest.java @@ -15,83 +15,30 @@ import java.util.Date; import org.junit.Before; import org.junit.Test; -public class OwnerTest { - private String login; - private String password; - private String md5Pass; +public class OwnerTest extends UserTest { private Pet[] pets; - private String newLogin; - private String newPassword; - private String newPasswordMD5; private Pet petOwned; private Pet petNotOwned; private Pet[] petsWithoutOwned; - - private String shortLogin; - private String longLogin; - private String shortPassword; @Before - public void setUp() throws Exception { - this.login = "Pepe"; - this.password = "pepepa"; - this.md5Pass = "41B0EEB2550AE3A43BF34DC2E8408E90"; + public void setUpOwner() throws Exception { this.pets = new Pet[] { new Pet("Lassie", AnimalType.DOG, new Date()), new Pet("Pajaroto", AnimalType.BIRD, new Date()) }; - this.newLogin = "José"; - this.newPassword = "josepass"; - this.newPasswordMD5 = "A3F6F4B40B24E2FD61F08923ED452F34"; this.petNotOwned = new Pet("Doraemon", AnimalType.CAT, new Date()); this.petOwned = this.pets[1]; this.petsWithoutOwned = copyOfRange(this.pets, 0, 1); - - this.shortLogin = ""; - this.longLogin = repeat('A', 101); - this.shortPassword = repeat('A', 5); } - - @Test - public void testOwnerStringString() { - final String[] logins = { login, "A", repeat('A', 100) }; - - for (String login : logins) { - final Owner owner = new Owner(login, password); - assertThat(owner.getLogin(), is(equalTo(login))); - assertThat(owner.getPassword(), is(equalTo(md5Pass))); - assertThat(owner.getPets(), is(emptyIterable())); - } + @Override + protected User newUser(String login, String password) { + return new Owner(login, password); } - @Test(expected = NullPointerException.class) - public void testOwnerStringStringNullLogin() { - new Owner(null, password); - } - - @Test(expected = NullPointerException.class) - public void testOwnerStringStringNullPassword() { - new Owner(login, null); - } - - @Test(expected = IllegalArgumentException.class) - public void testOwnerStringStringLoginTooShort() { - new Owner(shortLogin, password); - } - - @Test(expected = IllegalArgumentException.class) - public void testOwnerStringStringLoginTooLong() { - new Owner(longLogin, password); - } - - @Test(expected = IllegalArgumentException.class) - public void testOwnerStringStringPasswordTooShort() { - new Owner(login, shortPassword); - } - @Test public void testOwnerStringStringCollection() { final String[] logins = { login, "A", repeat('A', 100) }; @@ -149,79 +96,6 @@ public class OwnerTest { new Owner(login, password, new Pet[] { petNotOwned, null }); } - @Test - public void testSetLogin() { - final String[] logins = { login, "A", repeat('A', 100) }; - - for (String login : logins) { - final Owner owner = new Owner(login, password); - - owner.setLogin(newLogin); - - assertThat(owner.getLogin(), is(equalTo(newLogin))); - } - } - - @Test(expected = IllegalArgumentException.class) - public void testSetLoginTooShort() { - final Owner owner = new Owner(login, password); - - owner.setLogin(shortLogin); - } - - @Test(expected = IllegalArgumentException.class) - public void testSetLoginTooLong() { - final Owner owner = new Owner(login, password); - - owner.setLogin(longLogin); - } - - @Test - public void testSetPassword() { - final Owner owner = new Owner(login, password); - - owner.setPassword(newPasswordMD5); - - assertThat(owner.getPassword(), is(equalTo(newPasswordMD5))); - } - - @Test(expected = IllegalArgumentException.class) - public void testSetPasswordNoMD5() { - final Owner owner = new Owner(login, password); - - owner.setPassword("No MD5 password"); - } - - @Test(expected = NullPointerException.class) - public void testSetPasswordNullValue() { - final Owner owner = new Owner(login, password); - - owner.setPassword(null); - } - - @Test - public void testChangePassword() { - final Owner owner = new Owner(login, password); - - owner.changePassword(newPassword); - - assertThat(owner.getPassword(), is(equalTo(newPasswordMD5))); - } - - @Test(expected = NullPointerException.class) - public void testChangePasswordNull() { - final Owner owner = new Owner(login, password); - - owner.changePassword(null); - } - - @Test(expected = IllegalArgumentException.class) - public void testChangePasswordTooShort() { - final Owner owner = new Owner(login, password); - - owner.changePassword(shortPassword); - } - @Test public void testAddPet() { final Owner owner = new Owner(login, password); diff --git a/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/UserTest.java b/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/UserTest.java new file mode 100644 index 0000000..3455bf2 --- /dev/null +++ b/domain/src/test/java/es/uvigo/esei/xcs/domain/entities/UserTest.java @@ -0,0 +1,150 @@ +package es.uvigo.esei.xcs.domain.entities; + +import static org.apache.commons.lang3.StringUtils.repeat; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import org.junit.Before; +import org.junit.Test; + +public abstract class UserTest { + protected String login; + protected String password; + protected String md5Pass; + + protected String newLogin; + protected String newPassword; + protected String newPasswordMD5; + + protected String shortLogin; + protected String longLogin; + protected String shortPassword; + + @Before + public void setUpUser() throws Exception { + this.login = "Pepe"; + this.password = "pepepa"; + this.md5Pass = "41B0EEB2550AE3A43BF34DC2E8408E90"; + + this.newLogin = "José"; + this.newPassword = "josepass"; + this.newPasswordMD5 = "A3F6F4B40B24E2FD61F08923ED452F34"; + + this.shortLogin = ""; + this.longLogin = repeat('A', 101); + this.shortPassword = repeat('A', 5); + } + + protected abstract User newUser(String login, String password); + + @Test + public void testUserStringString() { + final String[] logins = { login, "A", repeat('A', 100) }; + + for (String login : logins) { + final User admin = newUser(login, password); + + assertThat(admin.getLogin(), is(equalTo(login))); + assertThat(admin.getPassword(), is(equalTo(md5Pass))); + } + } + + @Test(expected = NullPointerException.class) + public void testUserStringStringNullLogin() { + newUser(null, password); + } + + @Test(expected = NullPointerException.class) + public void testUserStringStringNullPassword() { + newUser(login, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testUserStringStringLoginTooShort() { + newUser(shortLogin, password); + } + + @Test(expected = IllegalArgumentException.class) + public void testUserStringStringLoginTooLong() { + newUser(longLogin, password); + } + + @Test(expected = IllegalArgumentException.class) + public void testUserStringStringPasswordTooShort() { + newUser(login, shortPassword); + } + + @Test + public void testSetLogin() { + final String[] logins = { login, "A", repeat('A', 100) }; + + for (String login : logins) { + final User admin = newUser(login, password); + + admin.setLogin(newLogin); + + assertThat(admin.getLogin(), is(equalTo(newLogin))); + } + } + + @Test(expected = IllegalArgumentException.class) + public void testSetLoginTooShort() { + final User admin = newUser(login, password); + + admin.setLogin(shortLogin); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetLoginTooLong() { + final User admin = newUser(login, password); + + admin.setLogin(longLogin); + } + + @Test + public void testSetPassword() { + final User admin = newUser(login, password); + + admin.setPassword(newPasswordMD5); + + assertThat(admin.getPassword(), is(equalTo(newPasswordMD5))); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetPasswordNoMD5() { + final User admin = newUser(login, password); + + admin.setPassword("No MD5 password"); + } + + @Test(expected = NullPointerException.class) + public void testSetPasswordNullValue() { + final User admin = newUser(login, password); + + admin.setPassword(null); + } + + @Test + public void testChangePassword() { + final User admin = newUser(login, password); + + admin.changePassword(newPassword); + + assertThat(admin.getPassword(), is(equalTo(newPasswordMD5))); + } + + @Test(expected = NullPointerException.class) + public void testChangePasswordNull() { + final User admin = newUser(login, password); + + admin.changePassword(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testChangePasswordTooShort() { + final User admin = newUser(login, password); + + admin.changePassword(shortPassword); + } +} diff --git a/service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToEntity.java b/service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToEntity.java new file mode 100644 index 0000000..c35be73 --- /dev/null +++ b/service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToEntity.java @@ -0,0 +1,56 @@ +package es.uvigo.esei.xcs.domain.entities; + +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.toList; +import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; + +import java.util.Collection; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +public abstract class IsEqualsToEntity extends TypeSafeMatcher { + protected final T expected; + private Consumer describeTo; + + public IsEqualsToEntity(T entity) { + this.expected = entity; + } + + @Override + public void describeTo(Description description) { + if (this.describeTo != null) { + this.describeTo.accept(description); + } + } + + protected void addTemplatedDescription(String attribute, Object expected) { + this.describeTo = d -> d.appendText(String.format( + "%s entity with value '%s' for %s", + this.expected.getClass().getSimpleName(), + expected, attribute + )); + } + + protected void addMatcherDescription(Matcher matcher) { + this.describeTo = matcher::describeTo; + } + + protected void clearDescribeTo() { + this.describeTo = null; + } + + @SafeVarargs + protected static Matcher> containsEntityInAnyOrder( + Function> converter, T ... entities + ) { + final Collection> ownerMatchers = stream(entities) + .map(converter) + .collect(toList()); + + return containsInAnyOrder(ownerMatchers); + } +} diff --git a/service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToOwner.java b/service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToOwner.java new file mode 100644 index 0000000..96dedc6 --- /dev/null +++ b/service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToOwner.java @@ -0,0 +1,65 @@ +package es.uvigo.esei.xcs.domain.entities; + +import static es.uvigo.esei.xcs.domain.entities.IsEqualsToPet.containsPetsWithoutRelationsInAnyOrder; + +import org.hamcrest.Factory; +import org.hamcrest.Matcher; + +public class IsEqualsToOwner extends IsEqualsToEntity { + private final boolean checkRelations; + + public IsEqualsToOwner(Owner owner, boolean checkRelations) { + super(owner); + this.checkRelations = checkRelations; + } + + @Override + protected boolean matchesSafely(Owner actual) { + this.clearDescribeTo(); + + if (actual == null) { + this.addTemplatedDescription("owner", expected.toString()); + return false; + } else if (!expected.getLogin().equals(actual.getLogin())) { + this.addTemplatedDescription("login", expected.getLogin()); + return false; + } else if (!expected.getPassword().equals(actual.getPassword())) { + this.addTemplatedDescription("password", expected.getPassword()); + return false; + } else if (this.checkRelations) { + final Matcher> petsMatcher = + containsPetsWithoutRelationsInAnyOrder( + expected.getPets().toArray(new Pet[0])); + + if (petsMatcher.matches(actual.getPets())) { + this.addMatcherDescription(petsMatcher); + + return true; + } else { + return false; + } + } else { + return true; + } + } + + @Factory + public static IsEqualsToOwner equalsToOwner(Owner owner) { + return new IsEqualsToOwner(owner, true); + } + + @Factory + public static IsEqualsToOwner equalsToOwnerWithoutRelations(Owner owner) { + return new IsEqualsToOwner(owner, false); + } + + @Factory + public static Matcher> containsOwnersInAnyOrder(Owner ... owners) { + return containsEntityInAnyOrder(IsEqualsToOwner::equalsToOwner, owners); + } + + @Factory + public static Matcher> containsOwnersWithoutRelationsInAnyOrder(Owner ... owners) { + return containsEntityInAnyOrder(IsEqualsToOwner::equalsToOwnerWithoutRelations, owners); + } +} diff --git a/service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToPet.java b/service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToPet.java new file mode 100644 index 0000000..50c063e --- /dev/null +++ b/service/src/test/java/es/uvigo/esei/xcs/domain/entities/IsEqualsToPet.java @@ -0,0 +1,68 @@ +package es.uvigo.esei.xcs.domain.entities; + +import static es.uvigo.esei.xcs.domain.entities.IsEqualsToOwner.equalsToOwnerWithoutRelations; + +import org.hamcrest.Factory; +import org.hamcrest.Matcher; + +public class IsEqualsToPet extends IsEqualsToEntity { + private final boolean checkRelations; + + public IsEqualsToPet(Pet pet, boolean checkRelations) { + super(pet); + this.checkRelations = checkRelations; + } + + @Override + protected boolean matchesSafely(Pet actual) { + this.clearDescribeTo(); + + if (actual == null) { + this.addTemplatedDescription("pet", expected.toString()); + return false; + } else if (this.expected.getId() != actual.getId()) { + this.addTemplatedDescription("id", expected.getId()); + return false; + } else if (!this.expected.getName().equals(actual.getName())) { + this.addTemplatedDescription("name", expected.getName()); + return false; + } else if (!this.expected.getAnimal().equals(actual.getAnimal())) { + this.addTemplatedDescription("animal", expected.getAnimal()); + return false; + } else if (this.expected.getBirth().getTime() != actual.getBirth().getTime()) { + this.addTemplatedDescription("birth", expected.getBirth()); + return false; + } else if (this.checkRelations) { + final IsEqualsToOwner equalsToOwner = equalsToOwnerWithoutRelations(this.expected.getOwner()); + + if (equalsToOwner.matchesSafely(actual.getOwner())) { + return true; + } else { + this.addMatcherDescription(equalsToOwner); + return false; + } + } else { + return true; + } + } + + @Factory + public static IsEqualsToPet equalsToPet(Pet pet) { + return new IsEqualsToPet(pet, true); + } + + @Factory + public static IsEqualsToPet equalsToPetWithoutRelations(Pet pet) { + return new IsEqualsToPet(pet, false); + } + + @Factory + public static Matcher> containsPetsInAnyOrder(Pet ... pets) { + return containsEntityInAnyOrder(IsEqualsToPet::equalsToPet, pets); + } + + @Factory + public static Matcher> containsPetsWithoutRelationsInAnyOrder(Pet ... pets) { + return containsEntityInAnyOrder(IsEqualsToPet::equalsToPetWithoutRelations, pets); + } +} diff --git a/service/src/test/java/es/uvigo/esei/xcs/domain/entities/OwnersDataset.java b/service/src/test/java/es/uvigo/esei/xcs/domain/entities/OwnersDataset.java new file mode 100644 index 0000000..35cbd06 --- /dev/null +++ b/service/src/test/java/es/uvigo/esei/xcs/domain/entities/OwnersDataset.java @@ -0,0 +1,88 @@ +package es.uvigo.esei.xcs.domain.entities; + +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.toSet; + +import java.util.Collection; +import java.util.Date; +import java.util.Set; + +public class OwnersDataset { + public static Owner owner(String login) { + return stream(owners()) + .filter(owner -> owner.getLogin().equals(login)) + .findFirst() + .orElseThrow(IllegalArgumentException::new); + } + + public static Pet pet(int id) { + return stream(pets()) + .filter(pet -> pet.getId() == id) + .findFirst() + .orElseThrow(IllegalArgumentException::new); + } + + public static Owner[] owners(String ... logins) { + final Set loginSet = stream(logins).collect(toSet()); + + return stream(owners()) + .filter(owner -> loginSet.contains(owner.getLogin())) + .toArray(Owner[]::new); + } + + public static Owner[] owners() { + return new Owner[] { + new Owner("pepe", "pepepass", + new Pet(1, "Pepecat", AnimalType.CAT, new Date(946684861000L))), + new Owner("juan", "juanpass", + new Pet(2, "Max", AnimalType.CAT, new Date(946684861000L)), + new Pet(3, "Juandog", AnimalType.DOG, new Date(946684861000L)) + ), + new Owner("ana", "anapass", + new Pet(4, "Anacat", AnimalType.CAT, new Date(946684861000L)), + new Pet(5, "Max", AnimalType.DOG, new Date(946684861000L)), + new Pet(6, "Anabird", AnimalType.BIRD, new Date(946684861000L)) + ), + new Owner("lorena", "lorenapass") + }; + } + + public static Pet[] pets() { + return stream(owners()) + .map(Owner::getPets) + .flatMap(Collection::stream) + .toArray(Pet[]::new); + } + + public static Owner newOwnerWithoutPets() { + return new Owner("jacinto", "jacintopass"); + } + + public static Owner newOwnerWithFreshPets() { + return new Owner("jacinto", "jacintopass", + new Pet("Jacintocat", AnimalType.CAT, new Date(946684861000L)), + new Pet("Jacintodo", AnimalType.DOG, new Date(946684861000L)), + new Pet("Jacintobird", AnimalType.BIRD, new Date(946684861000L)) + ); + } + + public static Owner newOwnerWithPersistentPets() { + return new Owner("jacinto", "jacintopass", + new Pet(7, "Jacintocat", AnimalType.CAT, new Date(946684861000L)), + new Pet(8, "Jacintodo", AnimalType.DOG, new Date(946684861000L)), + new Pet(9, "Jacintobird", AnimalType.BIRD, new Date(946684861000L)) + ); + } + + public static Owner ownerWithPets() { + return owners()[1]; + } + + public static Owner ownerWithoutPets() { + return owners()[3]; + } + + public static Pet newPet() { + return new Pet("Lorenacat", AnimalType.CAT, new Date(946684861000L)); + } +} -- 2.18.1