diff --git a/src/main/java/de/rwu/easydrop/service/mapping/ProductMapper.java b/src/main/java/de/rwu/easydrop/service/mapping/ProductMapper.java index 5d4a6d3..1b37a11 100644 --- a/src/main/java/de/rwu/easydrop/service/mapping/ProductMapper.java +++ b/src/main/java/de/rwu/easydrop/service/mapping/ProductMapper.java @@ -1,14 +1,44 @@ package de.rwu.easydrop.service.mapping; +import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.model.Product; + /** * Maps between Product, ProductDAO and ProductDTO. * - * TODO implement + * @since 0.2.0 * * @see Product * @see ProductDTO * @see ProductDAO */ -public class ProductMapper { +public final class ProductMapper { + /** + * Private constructor to prevent unwanted instantiation. + * + * @throws UnsupportedOperationException always + */ + private ProductMapper() throws UnsupportedOperationException { + throw new UnsupportedOperationException("This is a mapping class, don't instantiate it."); + } + + /** + * Creates a Product object from a corresponding DTO. + * + * @param dto Product Data Transfer Object + * @return Product + */ + public static Product mapProductFromDTO(final ProductDTO dto) { + Product product = new Product(); + + product.setAvailable(dto.isAvailable()); + product.setCurrentPrice(dto.getCurrentPrice()); + product.setDataOrigin(dto.getDataOrigin()); + product.setDeliveryPrice(dto.getDeliveryPrice()); + product.setMerchant(dto.getMerchant()); + product.setProductId(dto.getProductId()); + + return product; + } } diff --git a/src/main/java/de/rwu/easydrop/service/mapping/package-info.java b/src/main/java/de/rwu/easydrop/service/mapping/package-info.java index ab86051..944f66d 100644 --- a/src/main/java/de/rwu/easydrop/service/mapping/package-info.java +++ b/src/main/java/de/rwu/easydrop/service/mapping/package-info.java @@ -1,6 +1,6 @@ /** * Maps different formats of corresponding objects. * - * TODO implement + * @since 0.2.0 */ package de.rwu.easydrop.service.mapping; diff --git a/src/main/java/de/rwu/easydrop/service/validation/ProductValidator.java b/src/main/java/de/rwu/easydrop/service/validation/ProductValidator.java index 3c93108..fc48377 100644 --- a/src/main/java/de/rwu/easydrop/service/validation/ProductValidator.java +++ b/src/main/java/de/rwu/easydrop/service/validation/ProductValidator.java @@ -1,10 +1,56 @@ package de.rwu.easydrop.service.validation; +import java.util.HashSet; +import java.util.Set; + +import de.rwu.easydrop.exception.InvalidProductException; +import de.rwu.easydrop.model.Product; + /** * Confirms validity of Product data. * - * @since 0.1.0 + * @since 0.2.0 */ -public class ProductValidator { +public final class ProductValidator { + /** + * Private constructor to prevent unwanted instantiation. + * + * @throws UnsupportedOperationException always + */ + private ProductValidator() throws UnsupportedOperationException { + throw new UnsupportedOperationException("This is a validator class, don't instantiate it."); + } + + /** + * Makes sure a Product does not contain invalid information. + * + * @param product the Product + */ + public static void validate(final Product product) { + if (product.getCurrentPrice() == 0.00) { + throw new InvalidProductException("Current price cannot be 0.00"); + } + if (!isInValidDataOrigins(product.getDataOrigin())) { + throw new InvalidProductException("Unknown data source"); + } + if (product.getProductId().equals("")) { + throw new InvalidProductException("Product ID cannot be empty"); + } + } + + /** + * Checks whether a dataOrigin is within the set of valid ones. + * + * @param dataOrigin like "Amazon" + * @return true if valid + */ + public static boolean isInValidDataOrigins(final String dataOrigin) { + Set validOrigins = new HashSet<>(); + + validOrigins.add("Amazon"); + validOrigins.add("eBay"); + + return validOrigins.contains(dataOrigin); + } } diff --git a/src/main/java/de/rwu/easydrop/service/validation/package-info.java b/src/main/java/de/rwu/easydrop/service/validation/package-info.java index 6b45561..a74f45c 100644 --- a/src/main/java/de/rwu/easydrop/service/validation/package-info.java +++ b/src/main/java/de/rwu/easydrop/service/validation/package-info.java @@ -1,6 +1,6 @@ /** * Supports validation processes. * - * TODO implement + * @since 0.2.0 */ package de.rwu.easydrop.service.validation; diff --git a/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java b/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java new file mode 100644 index 0000000..6dbf741 --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/mapping/ProductMapperTest.java @@ -0,0 +1,56 @@ +package de.rwu.easydrop.service.mapping; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; + +import org.junit.jupiter.api.Test; + +import de.rwu.easydrop.api.dto.ProductDTO; +import de.rwu.easydrop.model.Product; + +class ProductMapperTest { + @Test + void testConstructorIsPrivate() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + // Check for private constructor + Constructor constructor = ProductMapper.class.getDeclaredConstructor(); + assertTrue(Modifier.isPrivate(constructor.getModifiers())); + + // Make sure exception is thrown when instantiating + constructor.setAccessible(true); + assertThrows(InvocationTargetException.class, () -> { + constructor.newInstance(); + }); + } + + @Test + void mapProductFromDTO_ReturnsProductWithMappedFields() { + // Arrange + ProductDTO dto = createProductDTO(); + + // Act + Product product = ProductMapper.mapProductFromDTO(dto); + + // Assert + assertEquals(dto.isAvailable(), product.isAvailable()); + assertEquals(dto.getCurrentPrice(), product.getCurrentPrice()); + assertEquals(dto.getDataOrigin(), product.getDataOrigin()); + assertEquals(dto.getDeliveryPrice(), product.getDeliveryPrice()); + assertEquals(dto.getMerchant(), product.getMerchant()); + assertEquals(dto.getProductId(), product.getProductId()); + } + + private ProductDTO createProductDTO() { + ProductDTO dto = new ProductDTO("12345", "Amazon"); + dto.setAvailable(true); + dto.setCurrentPrice(9.99); + dto.setDeliveryPrice(2.50); + dto.setMerchant("Example Merchant"); + return dto; + } +} diff --git a/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java b/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java new file mode 100644 index 0000000..7827bbb --- /dev/null +++ b/src/test/java/de/rwu/easydrop/service/validation/ProductValidatorTest.java @@ -0,0 +1,109 @@ +package de.rwu.easydrop.service.validation; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import de.rwu.easydrop.exception.InvalidProductException; +import de.rwu.easydrop.model.Product; + +class ProductValidatorTest { + + @Test + void testConstructorIsPrivate() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + // Check for private constructor + Constructor constructor = ProductValidator.class.getDeclaredConstructor(); + assertTrue(Modifier.isPrivate(constructor.getModifiers())); + + // Make sure exception is thrown when instantiating + constructor.setAccessible(true); + assertThrows(InvocationTargetException.class, () -> { + constructor.newInstance(); + }); + } + + @Test + void validate_ValidProduct_NoExceptionThrown() { + // Arrange + Product product = new Product(); + product.setCurrentPrice(9.99); + product.setDataOrigin("Amazon"); + product.setProductId("12345"); + + // Act and Assert + assertDoesNotThrow(() -> ProductValidator.validate(product)); + } + + @Test + void isInValidDataOrigins_ValidDataOrigin_ReturnsTrue() { + // Arrange + String dataOrigin = "Amazon"; + + // Act + boolean result = ProductValidator.isInValidDataOrigins(dataOrigin); + + // Assert + assertTrue(result); + } + + @Test + void isInValidDataOrigins_InvalidDataOrigin_ReturnsFalse() { + // Arrange + String dataOrigin = "UnknownOrigin"; + + // Act + boolean result = ProductValidator.isInValidDataOrigins(dataOrigin); + + // Assert + assertFalse(result); + } + + @ParameterizedTest + @MethodSource("invalidProductProvider") + void validate_InvalidProduct_ThrowsInvalidProductException(Product product) { + // Act and Assert + assertThrows(InvalidProductException.class, () -> ProductValidator.validate(product)); + } + + static Stream invalidProductProvider() { + return Stream.of( + createProductWithZeroPrice(), + createProductWithUnknownDataOrigin(), + createProductWithEmptyProductId()); + } + + private static Product createProductWithZeroPrice() { + Product product = new Product(); + product.setCurrentPrice(0.00); + product.setDataOrigin("Amazon"); + product.setProductId("12345"); + return product; + } + + private static Product createProductWithUnknownDataOrigin() { + Product product = new Product(); + product.setCurrentPrice(9.99); + product.setDataOrigin("UnknownOrigin"); + product.setProductId("12345"); + return product; + } + + private static Product createProductWithEmptyProductId() { + Product product = new Product(); + product.setCurrentPrice(9.99); + product.setDataOrigin("Amazon"); + product.setProductId(""); + return product; + } +}