From 2cd92d4e2cfef43f2d34d8c25df59ee758c343ce Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Sun, 28 Apr 2019 12:02:01 +0200 Subject: [PATCH] generalized AccessMappingsUnitTestBase --- .../dto/AccessMappingsUnitTestBase.java | 105 ++++++++++++++++-- .../service/dto/AssetDTOUnitTest.java | 62 ++++------- 2 files changed, 117 insertions(+), 50 deletions(-) diff --git a/src/test/java/org/hostsharing/hsadminng/service/dto/AccessMappingsUnitTestBase.java b/src/test/java/org/hostsharing/hsadminng/service/dto/AccessMappingsUnitTestBase.java index cf13506b..3ee82187 100644 --- a/src/test/java/org/hostsharing/hsadminng/service/dto/AccessMappingsUnitTestBase.java +++ b/src/test/java/org/hostsharing/hsadminng/service/dto/AccessMappingsUnitTestBase.java @@ -1,14 +1,19 @@ package org.hostsharing.hsadminng.service.dto; +import org.apache.commons.lang3.RandomUtils; import org.hostsharing.hsadminng.service.accessfilter.AccessFor; import org.hostsharing.hsadminng.service.accessfilter.Role; +import org.hostsharing.hsadminng.service.util.ReflectionUtil; +import org.junit.Test; import java.lang.reflect.Field; import java.util.HashSet; +import java.util.Objects; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import static org.apache.commons.lang3.StringUtils.removeEnd; import static org.assertj.core.api.Assertions.assertThat; /** @@ -16,28 +21,71 @@ import static org.assertj.core.api.Assertions.assertThat; * DTOs which implement AccessMapping are more like a DSL, * this base class should be used to enforce its required structure. */ -public abstract class AccessMappingsUnitTestBase { +public abstract class AccessMappingsUnitTestBase { - protected AccessRightsMatcher initAccesFor(final Class dtoClass, final Role role) { + @Test + public void shouldConvertToString() { + final D sampleDto = createSampleDto(1234L); + final String dtoAsString = dtoToString(sampleDto); + assertThat(sampleDto.toString()).isEqualTo(dtoAsString); + } + + @Test + @SuppressWarnings("all") + public void shouldImplementEqualsJustUsingClassAndId() { + final D dto = createSampleDto(1234L); + assertThat(dto.equals(dto)).isTrue(); + + final D dtoWithSameId = createRandomDto(1234L); + assertThat(dto.equals(dtoWithSameId)).isTrue(); + + final D dtoWithAnotherId = createRandomDto(RandomUtils.nextLong(2000, 9999)); + assertThat(dtoWithAnotherId.equals(dtoWithSameId)).isFalse(); + + final D dtoWithoutId = createRandomDto(null); + assertThat(dto.equals(dtoWithoutId)).isFalse(); + assertThat(dtoWithoutId.equals(dto)).isFalse(); + + assertThat(dto.equals(null)).isFalse(); + assertThat(dto.equals("")).isFalse(); + } + + @Test + public void shouldImplementHashCodeJustUsingClassAndId() { + final long randomId = RandomUtils.nextLong(); + final D dto = createSampleDto(randomId); + assertThat(dto.hashCode()).isEqualTo(Objects.hashCode(randomId)); + + final D dtoWithoutId = createRandomDto(null); + assertThat(dtoWithoutId.hashCode()).isEqualTo(Objects.hashCode(null)); + } + + protected abstract D createSampleDto(final Long id); + + protected abstract D createRandomDto(final Long id); + + protected AccessRightsMatcher initAccessFor(final Class dtoClass, final Role role) { return new AccessRightsMatcher(dtoClass, role, AccessFor::init); } - protected AccessRightsMatcher updateAccesFor(final Class dtoClass, final Role role) { + protected AccessRightsMatcher updateAccessFor(final Class dtoClass, final Role role) { return new AccessRightsMatcher(dtoClass, role, AccessFor::update); } - protected AccessRightsMatcher readAccesFor(final Class dtoClass, final Role role) { + protected AccessRightsMatcher readAccessFor(final Class dtoClass, final Role role) { return new AccessRightsMatcher(dtoClass, role, AccessFor::read); } + // This class should have the same generics as the outer class, but then the + // method references (AccessFor::*) can't be resolved anymore by the Java compiler. protected static class AccessRightsMatcher { - private final Class dtoClass; + private final Object dtoClass; private final Role role; private final String[] namesOfFieldsWithAccessForAnnotation; private final String[] namesOfAccessibleFields; - AccessRightsMatcher(final Class dtoClass, final Role role, final Function access) { + AccessRightsMatcher(final Class dtoClass, final Role role, final Function access) { this.dtoClass = dtoClass; this.role = role; @@ -61,7 +109,7 @@ public abstract class AccessMappingsUnitTestBase { } - private static Set determineFieldsWithAccessForAnnotation(final Class dtoClass) { + private static Set determineFieldsWithAccessForAnnotation(final Class dtoClass) { final Set fieldsWithAccessForAnnotation = new HashSet<>(); @@ -83,4 +131,47 @@ public abstract class AccessMappingsUnitTestBase { return false; } } + + private String dtoToString(final D dto) { + final StringBuilder fieldValues = new StringBuilder(); + boolean firstField = true; + for (Field field : dto.getClass().getDeclaredFields()) { + if (field.isAnnotationPresent(AccessFor.class)) { + firstField = appendCommaOptionally(fieldValues, firstField); + appendFieldName(fieldValues, field); + appendFieldValue(dto, fieldValues, field); + } + } + return dto.getClass().getSimpleName() + "{" + fieldValues + "}"; + } + + private void appendFieldValue(final D dto, final StringBuilder fieldValues, final Field field) { + final Object value = ReflectionUtil.getValue(dto, field); + final boolean inQuotes = isJHipsterToStringUsingQuotes(field); + if (inQuotes) { + fieldValues.append("'"); + } + fieldValues.append(value); + if (inQuotes) { + fieldValues.append("'"); + } + } + + private void appendFieldName(final StringBuilder fieldValues, final Field field) { + fieldValues.append(removeEnd(field.getName(), "Id")); + fieldValues.append("="); + } + + private boolean appendCommaOptionally(final StringBuilder fieldValues, boolean firstField) { + if (firstField) { + firstField = false; + } else { + fieldValues.append(", "); + } + return firstField; + } + + private boolean isJHipsterToStringUsingQuotes(final Field field) { + return !Number.class.isAssignableFrom(field.getType()) && !Boolean.class.isAssignableFrom(field.getType()); + } } diff --git a/src/test/java/org/hostsharing/hsadminng/service/dto/AssetDTOUnitTest.java b/src/test/java/org/hostsharing/hsadminng/service/dto/AssetDTOUnitTest.java index 759f37fd..06d7604c 100644 --- a/src/test/java/org/hostsharing/hsadminng/service/dto/AssetDTOUnitTest.java +++ b/src/test/java/org/hostsharing/hsadminng/service/dto/AssetDTOUnitTest.java @@ -9,82 +9,59 @@ import org.junit.Test; import java.math.BigDecimal; import java.time.LocalDate; -import static org.assertj.core.api.Assertions.assertThat; - -public class AssetDTOUnitTest extends AccessMappingsUnitTestBase { +public class AssetDTOUnitTest extends AccessMappingsUnitTestBase { @Test public void shouldHaveProperAccessForAdmin() { - initAccesFor(AssetDTO.class, Role.ADMIN).shouldBeExactlyFor( + initAccessFor(AssetDTO.class, Role.ADMIN).shouldBeExactlyFor( "membershipId", "documentDate", "amount", "action", "valueDate", "remark"); - updateAccesFor(AssetDTO.class, Role.ADMIN).shouldBeExactlyFor("remark"); - readAccesFor(AssetDTO.class, Role.ADMIN).shouldBeForAllFields(); + updateAccessFor(AssetDTO.class, Role.ADMIN).shouldBeExactlyFor("remark"); + readAccessFor(AssetDTO.class, Role.ADMIN).shouldBeForAllFields(); } @Test public void shouldHaveProperAccessForContractualContact() { - initAccesFor(AssetDTO.class, Role.CONTRACTUAL_CONTACT).shouldBeForNothing(); - updateAccesFor(AssetDTO.class, Role.CONTRACTUAL_CONTACT).shouldBeForNothing(); - readAccesFor(AssetDTO.class, Role.CONTRACTUAL_CONTACT).shouldBeExactlyFor( + initAccessFor(AssetDTO.class, Role.CONTRACTUAL_CONTACT).shouldBeForNothing(); + updateAccessFor(AssetDTO.class, Role.CONTRACTUAL_CONTACT).shouldBeForNothing(); + readAccessFor(AssetDTO.class, Role.CONTRACTUAL_CONTACT).shouldBeExactlyFor( "id", "membershipId", "documentDate", "amount", "action", "valueDate", "membershipDisplayLabel"); } @Test public void shouldHaveNoAccessForTechnicalContact() { - initAccesFor(AssetDTO.class, Role.TECHNICAL_CONTACT).shouldBeForNothing(); - updateAccesFor(AssetDTO.class, Role.TECHNICAL_CONTACT).shouldBeForNothing(); - readAccesFor(AssetDTO.class, Role.TECHNICAL_CONTACT).shouldBeForNothing(); + initAccessFor(AssetDTO.class, Role.TECHNICAL_CONTACT).shouldBeForNothing(); + updateAccessFor(AssetDTO.class, Role.TECHNICAL_CONTACT).shouldBeForNothing(); + readAccessFor(AssetDTO.class, Role.TECHNICAL_CONTACT).shouldBeForNothing(); } @Test public void shouldHaveNoAccessForNormalUsersWithinCustomerRealm() { - initAccesFor(AssetDTO.class, Role.ANY_CUSTOMER_USER).shouldBeForNothing(); - updateAccesFor(AssetDTO.class, Role.ANY_CUSTOMER_USER).shouldBeForNothing(); - readAccesFor(AssetDTO.class, Role.ANY_CUSTOMER_USER).shouldBeForNothing(); - } - - @Test - public void shouldConvertToString() { - final AssetDTO dto = createDto(1234L); - assertThat(dto.toString()).isEqualTo("AssetDTO{id=1234, documentDate='2000-12-07', valueDate='2000-12-18', action='PAYMENT', amount=512.01, remark='Some Remark', membership=888, membershipDisplayLabel='Some Membership'}"); - } - - @Test - public void shouldImplementEqualsJustUsingClassAndId() { - final AssetDTO dto = createDto(1234L); - assertThat(dto.equals(dto)).isTrue(); - - final AssetDTO dtoWithSameId = createRandomDto(1234L); - assertThat(dto.equals(dtoWithSameId)).isTrue(); - - final AssetDTO dtoWithAnotherId = createRandomDto(RandomUtils.nextLong(2000, 9999)); - assertThat(dtoWithAnotherId.equals(dtoWithSameId)).isFalse(); - - final AssetDTO dtoWithoutId = createRandomDto(null); - assertThat(dto.equals(dtoWithoutId)).isFalse(); - assertThat(dtoWithoutId.equals(dto)).isFalse(); - - assertThat(dto.equals(null)).isFalse(); - assertThat(dto.equals("")).isFalse(); + initAccessFor(AssetDTO.class, Role.ANY_CUSTOMER_USER).shouldBeForNothing(); + updateAccessFor(AssetDTO.class, Role.ANY_CUSTOMER_USER).shouldBeForNothing(); + readAccessFor(AssetDTO.class, Role.ANY_CUSTOMER_USER).shouldBeForNothing(); } // --- only test fixture below --- - private AssetDTO createDto(final Long id) { + @Override + public AssetDTO createSampleDto(final Long id) { final AssetDTO dto = new AssetDTO(); dto.setId(id); dto.setDocumentDate(LocalDate.parse("2000-12-07")); dto.setAmount(new BigDecimal("512.01")); dto.setAction(AssetAction.PAYMENT); dto.setRemark("Some Remark"); + dto.setRemark(null); dto.setValueDate(LocalDate.parse("2000-12-18")); dto.setMembershipId(888L); + dto.setMembershipId(null); dto.setMembershipDisplayLabel("Some Membership"); return dto; } - private AssetDTO createRandomDto(final Long id) { + @Override + public AssetDTO createRandomDto(final Long id) { final AssetDTO dto = new AssetDTO(); dto.setId(id); final LocalDate randomDate = LocalDate.parse("2000-12-07").plusDays(RandomUtils.nextInt(1, 999)); @@ -97,5 +74,4 @@ public class AssetDTOUnitTest extends AccessMappingsUnitTestBase { dto.setMembershipDisplayLabel(RandomStringUtils.randomAlphabetic(20)); return dto; } - }