From 54b62371880eef5c283d64eb870ea92ca9b5b7d1 Mon Sep 17 00:00:00 2001 From: verboomp Date: Tue, 3 Feb 2026 10:33:59 +0100 Subject: [PATCH] cleanup and unit tests --- hartmann-foto-documentation-app/pom.xml | 6 +- .../core/query/QueryService.java | 8 - .../core/service/CustomerPictureService.java | 42 +-- .../core/service/PictureService.java | 5 +- .../core/utils/CalendarUtil.java | 58 +++++ .../core/utils/EvaluationUtil.java | 20 ++ .../rest/CustomerPictureResource.java | 23 +- .../rest/CustomerResource.java | 2 +- .../rest/PictureResource.java | 8 +- .../core/utils/CalendarUtilTest.java | 230 +++++++++++++++++ .../core/utils/EvaluationUtilTest.java | 60 +++++ .../core/utils/ImageUtilTest.java | 240 ++++++++++++++++++ .../core/utils/PdfUtilsTest.java | 2 +- .../rest/CustomerResourceTest.java | 31 ++- .../rest/PictureResourceTest.java | 82 +++++- 15 files changed, 735 insertions(+), 82 deletions(-) create mode 100644 hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/utils/CalendarUtil.java create mode 100644 hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/utils/EvaluationUtil.java create mode 100644 hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/CalendarUtilTest.java create mode 100644 hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/EvaluationUtilTest.java create mode 100644 hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/ImageUtilTest.java diff --git a/hartmann-foto-documentation-app/pom.xml b/hartmann-foto-documentation-app/pom.xml index 92a347c..920d058 100644 --- a/hartmann-foto-documentation-app/pom.xml +++ b/hartmann-foto-documentation-app/pom.xml @@ -39,9 +39,9 @@ - org.apache.pdfbox - pdfbox - 3.0.5 + org.apache.pdfbox + pdfbox + 3.0.5 diff --git a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/query/QueryService.java b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/query/QueryService.java index 22ce90f..2ba80c7 100644 --- a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/query/QueryService.java +++ b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/query/QueryService.java @@ -50,14 +50,6 @@ public class QueryService { } } - public T callNamedQueryList(String namedQuery, Param... objects) { - Query query = eManager.createNamedQuery(namedQuery); - for (Param param : objects) { - query.setParameter(param.name(), param.value()); - } - return (T) query.getResultList(); - } - public int callNamedQueryUpdate(String namedQuery, Param... objects) { Query query = eManager.createNamedQuery(namedQuery); for (Param param : objects) { diff --git a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/service/CustomerPictureService.java b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/service/CustomerPictureService.java index 065968c..3784a7d 100644 --- a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/service/CustomerPictureService.java +++ b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/service/CustomerPictureService.java @@ -1,12 +1,8 @@ package marketing.heyday.hartmann.fotodocumentation.core.service; -import java.text.ParseException; import java.util.*; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.time.DateUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import jakarta.annotation.security.PermitAll; import jakarta.ejb.LocalBean; @@ -17,6 +13,7 @@ import jakarta.persistence.criteria.*; import marketing.heyday.hartmann.fotodocumentation.core.model.Customer; import marketing.heyday.hartmann.fotodocumentation.core.model.Picture; import marketing.heyday.hartmann.fotodocumentation.core.query.Param; +import marketing.heyday.hartmann.fotodocumentation.core.utils.CalendarUtil; import marketing.heyday.hartmann.fotodocumentation.core.utils.PdfUtils; import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerListValue; import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerPictureValue; @@ -35,11 +32,13 @@ import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerValue; @LocalBean @PermitAll public class CustomerPictureService extends AbstractService { - private static final Log LOG = LogFactory.getLog(CustomerPictureService.class); @Inject private PdfUtils pdfUtils; + @Inject + private CalendarUtil calendarUtil; + public boolean addCustomerPicture(CustomerPictureValue customerPictureValue) { Optional customerOpt = queryService.callNamedQuerySingleResult(Customer.FIND_BY_NUMBER, new Param(Customer.PARAM_NUMBER, customerPictureValue.customerNumber())); Customer customer = customerOpt.orElseGet(() -> new Customer.Builder().customerNumber(customerPictureValue.customerNumber()).name(customerPictureValue.pharmacyName()) @@ -78,23 +77,10 @@ public class CustomerPictureService extends AbstractService { if (StringUtils.isNotBlank(queryStr)) { // check if it contains a date - Date date = null; - try { - date = DateUtils.parseDate(queryStr, Locale.GERMAN, "dd.MM.yyyy", "d.M.yyyy", "dd.MM.yy", "d. MMMM yyyy", "dd MMMM yyyy", "dd-MM-yyyy"); - - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal.set(Calendar.HOUR_OF_DAY, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MILLISECOND, 0); - Date startOfDay = cal.getTime(); - - cal.set(Calendar.HOUR_OF_DAY, 23); - cal.set(Calendar.MINUTE, 59); - cal.set(Calendar.SECOND, 59); - cal.set(Calendar.MILLISECOND, 999); - Date endOfDay = cal.getTime(); + Date date = calendarUtil.parse(queryStr); + if (date != null) { + Date startOfDay = calendarUtil.getStartOfDay(date); + Date endOfDay = calendarUtil.getEndOfDay(date); Fetch picturesFetch = customerRoot.fetch("pictures", JoinType.LEFT); @SuppressWarnings("unchecked") @@ -103,11 +89,7 @@ public class CustomerPictureService extends AbstractService { var predicateDate = builder.between(pictures.get("pictureDate"), startOfDay, endOfDay); predicates.add(predicateDate); - } catch (ParseException e) { - LOG.trace("Failed to find date in queryStr " + queryStr); - } - - if (date == null) { + } else { String param = "%" + StringUtils.trimToEmpty(queryStr).toLowerCase() + "%"; var predicateName = builder.like(builder.lower(customerRoot.get("name")), param); var predicateNr = builder.like(builder.lower(customerRoot.get("customerNumber")), param); @@ -123,8 +105,6 @@ public class CustomerPictureService extends AbstractService { criteriaQuery = criteriaQuery.where(builder.and(predicates.toArray(new Predicate[0]))); } - //criteriaQuery = criteriaQuery.orderBy(builder.asc(builder.lower(customerRoot.get("name")))); //FIXME: this causes errors - TypedQuery typedQuery = entityManager.createQuery(criteriaQuery); List customers = typedQuery.getResultList(); customers.forEach(c -> c.getPictures().size()); @@ -143,14 +123,14 @@ public class CustomerPictureService extends AbstractService { public byte[] getExport(Long id, Long pictureId) { Customer customer = entityManager.find(Customer.class, id); if (customer == null) { - return null; + return new byte[0]; } List pictures = customer.getPictures().stream().sorted((x, y) -> x.getPictureDate().compareTo(y.getPictureDate())).toList(); if (pictureId != null) { Optional pictureOpt = customer.getPictures().stream().filter(p -> p.getPictureId().equals(pictureId)).findFirst(); - pictures = pictureOpt.map(p -> Arrays.asList(p)).orElse(pictures); + pictures = pictureOpt.map(Arrays::asList).orElse(pictures); } return pdfUtils.createPdf(customer, pictures); diff --git a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/service/PictureService.java b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/service/PictureService.java index 72c3dda..43efeb2 100644 --- a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/service/PictureService.java +++ b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/service/PictureService.java @@ -1,7 +1,5 @@ package marketing.heyday.hartmann.fotodocumentation.core.service; -import java.util.Base64; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -52,9 +50,8 @@ public class PictureService extends AbstractService { public byte[] getImage(Long id, int size) { try { Picture entity = entityManager.getReference(Picture.class, id); - String base64 = entity.getImage(); - return Base64.getDecoder().decode(base64); + return imageUtil.getImage(base64, size); } catch (EntityNotFoundException e) { LOG.warn("Failed to get image for id " + id, e); ejbContext.setRollbackOnly(); diff --git a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/utils/CalendarUtil.java b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/utils/CalendarUtil.java new file mode 100644 index 0000000..3dbd49d --- /dev/null +++ b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/utils/CalendarUtil.java @@ -0,0 +1,58 @@ +package marketing.heyday.hartmann.fotodocumentation.core.utils; + +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +import org.apache.commons.lang3.time.DateUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + *

Copyright: Copyright (c) 2024

+ *

Company: heyday Marketing GmbH

+ * @author Patrick Verboom + * @version 1.0 + * + * created: 3 Feb 2026 + */ + +public class CalendarUtil { + private static final Log LOG = LogFactory.getLog(CalendarUtil.class); + private static int HOUR_OF_DAY = 23; + private static int MINUTE = 59; + private static int SECOND = 59; + private static int MILLISECOND = 999; + + public Date parse(String query) { + try { + return DateUtils.parseDate(query, Locale.GERMAN, "dd.MM.yyyy", "d.M.yyyy", "dd.MM.yy", "d. MMMM yyyy", "dd MMMM yyyy", "dd-MM-yyyy"); + } catch (ParseException e) { + LOG.trace("Failed to find date in queryStr " + query); + return null; + } + } + + public Date getStartOfDay(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + + public Date getEndOfDay(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(Calendar.HOUR_OF_DAY, HOUR_OF_DAY); + + cal.set(Calendar.MINUTE, MINUTE); + cal.set(Calendar.SECOND, SECOND); + cal.set(Calendar.MILLISECOND, MILLISECOND); + return cal.getTime(); + } +} diff --git a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/utils/EvaluationUtil.java b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/utils/EvaluationUtil.java new file mode 100644 index 0000000..95536f1 --- /dev/null +++ b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/core/utils/EvaluationUtil.java @@ -0,0 +1,20 @@ +package marketing.heyday.hartmann.fotodocumentation.core.utils; + +/** + * + *

Copyright: Copyright (c) 2024

+ *

Company: heyday Marketing GmbH

+ * @author Patrick Verboom + * @version 1.0 + * + * created: 3 Feb 2026 + */ + +public class EvaluationUtil { + private static final int MIN_VALUE = 1; + private static final int MAX_VALUE = 1; + + public boolean isValid(Integer value) { + return (value == null || value < MIN_VALUE || value > MAX_VALUE); + } +} diff --git a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerPictureResource.java b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerPictureResource.java index 636adf5..c23714a 100644 --- a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerPictureResource.java +++ b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerPictureResource.java @@ -1,27 +1,18 @@ package marketing.heyday.hartmann.fotodocumentation.rest; -import java.util.Optional; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.jboss.resteasy.annotations.GZIP; -import org.wildfly.security.auth.server.SecurityIdentity; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import jakarta.ejb.EJB; import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Inject; -import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.Status; import marketing.heyday.hartmann.fotodocumentation.core.service.CustomerPictureService; -import marketing.heyday.hartmann.fotodocumentation.core.utils.LoginUtils; import marketing.heyday.hartmann.fotodocumentation.rest.jackson.JsonSchemaValidate; import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerPictureValue; @@ -37,27 +28,17 @@ import marketing.heyday.hartmann.fotodocumentation.rest.vo.CustomerPictureValue; @RequestScoped @Path("customer-picture") public class CustomerPictureResource { - private static final Log LOG = LogFactory.getLog(CustomerPictureResource.class); - + @EJB private CustomerPictureService customerPictureService; - @Inject - private LoginUtils loginUtils; - @GZIP @POST @Path("") @Consumes(MediaType.APPLICATION_JSON) @Operation(summary = "Add Customer Image to database") @ApiResponse(responseCode = "200", description = "Add successfull") - public Response doAddCustomerPicture(@Context HttpServletRequest httpServletRequest, @JsonSchemaValidate("schema/customer_picture_add.json") CustomerPictureValue customerPictureValue) { - /*Optional identity = loginUtils.authenticate(httpServletRequest); - if (identity.isEmpty()) { - LOG.debug("identity empty login invalid"); - return Response.status(Status.UNAUTHORIZED).build(); - } - */ + public Response doAddCustomerPicture(@JsonSchemaValidate("schema/customer_picture_add.json") CustomerPictureValue customerPictureValue) { boolean success = customerPictureService.addCustomerPicture(customerPictureValue); return success ? Response.ok().build() : Response.status(Status.BAD_REQUEST).build(); } diff --git a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerResource.java b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerResource.java index 2177b46..e2f5f3f 100644 --- a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerResource.java +++ b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerResource.java @@ -81,7 +81,7 @@ public class CustomerResource { LOG.debug("Create export for customer " + id + " with optional param " + pictureId); byte[] pdf = customerPictureService.getExport(id, pictureId); - if (pdf == null) { + if (pdf.length == 0) { return Response.status(Status.NOT_FOUND).build(); } diff --git a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/PictureResource.java b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/PictureResource.java index 7f094f1..bda5cf6 100644 --- a/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/PictureResource.java +++ b/hartmann-foto-documentation-app/src/main/java/marketing/heyday/hartmann/fotodocumentation/rest/PictureResource.java @@ -10,12 +10,14 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import jakarta.ejb.EJB; import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.ResponseBuilder; import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.core.StreamingOutput; import marketing.heyday.hartmann.fotodocumentation.core.service.PictureService; +import marketing.heyday.hartmann.fotodocumentation.core.utils.EvaluationUtil; import marketing.heyday.hartmann.fotodocumentation.core.utils.StorageUtils.StorageState; /** @@ -34,6 +36,10 @@ public class PictureResource { @EJB private PictureService pictureService; + + @Inject + private EvaluationUtil evaluationUtil; + @DELETE @Path("{id}") @@ -52,7 +58,7 @@ public class PictureResource { @Operation(summary = "Update evaluation for picture data to database") @ApiResponse(responseCode = "200", description = "Task successfully updated") public Response doUpdateEvaluation(@PathParam("id") Long id, @QueryParam("evaluation") Integer value) { - if (value == null || value < 1 || value > 3) { + if (!evaluationUtil.isValid(value)) { return Response.status(Status.BAD_REQUEST).build(); } StorageState state = pictureService.updateEvaluationStatus(id, value); diff --git a/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/CalendarUtilTest.java b/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/CalendarUtilTest.java new file mode 100644 index 0000000..9e680c6 --- /dev/null +++ b/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/CalendarUtilTest.java @@ -0,0 +1,230 @@ +package marketing.heyday.hartmann.fotodocumentation.core.utils; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Calendar; +import java.util.Date; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * + *

Copyright: Copyright (c) 2024

+ *

Company: heyday Marketing GmbH

+ * @author Patrick Verboom + * @version 1.0 + * + * created: 3 Feb 2026 + */ +class CalendarUtilTest { + + private CalendarUtil calendarUtil; + + @BeforeEach + void setUp() { + calendarUtil = new CalendarUtil(); + } + + // --- parse --- + + @Test + void parse_ddMMyyyyDot_returnsDate() { + Date result = calendarUtil.parse("15.03.2026"); + + assertNotNull(result); + Calendar cal = toCalendar(result); + assertEquals(15, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(Calendar.MARCH, cal.get(Calendar.MONTH)); + assertEquals(2026, cal.get(Calendar.YEAR)); + } + + @Test + void parse_dMyyyyDot_returnsDate() { + Date result = calendarUtil.parse("5.3.2026"); + + assertNotNull(result); + Calendar cal = toCalendar(result); + assertEquals(5, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(Calendar.MARCH, cal.get(Calendar.MONTH)); + assertEquals(2026, cal.get(Calendar.YEAR)); + } + + @Test + void parse_ddMMyy_returnsDate() { + Date result = calendarUtil.parse("15.03.26"); + + assertNotNull(result); + Calendar cal = toCalendar(result); + assertEquals(15, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(Calendar.MARCH, cal.get(Calendar.MONTH)); + } + + @Test + void parse_ddMMyyyyDash_returnsDate() { + Date result = calendarUtil.parse("15-03-2026"); + + assertNotNull(result); + Calendar cal = toCalendar(result); + assertEquals(15, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(Calendar.MARCH, cal.get(Calendar.MONTH)); + assertEquals(2026, cal.get(Calendar.YEAR)); + } + + @Test + void parse_germanMonthName_dMMMMyyyy_returnsDate() { + Date result = calendarUtil.parse("5. Januar 2026"); + + assertNotNull(result); + Calendar cal = toCalendar(result); + assertEquals(5, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(Calendar.JANUARY, cal.get(Calendar.MONTH)); + assertEquals(2026, cal.get(Calendar.YEAR)); + } + + @Test + void parse_germanMonthName_ddMMMMyyyy_returnsDate() { + Date result = calendarUtil.parse("15 Dezember 2025"); + + assertNotNull(result); + Calendar cal = toCalendar(result); + assertEquals(15, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(Calendar.DECEMBER, cal.get(Calendar.MONTH)); + assertEquals(2025, cal.get(Calendar.YEAR)); + } + + @Test + void parse_invalidString_returnsNull() { + assertNull(calendarUtil.parse("not a date")); + } + + @Test + void parse_emptyString_returnsNull() { + assertNull(calendarUtil.parse("")); + } + + @Test + void parse_null_throwsException() { + assertThrows(IllegalArgumentException.class, () -> calendarUtil.parse(null)); + } + + // --- getStartOfDay --- + + @Test + void getStartOfDay_returnsDateAtMidnight() { + Calendar input = Calendar.getInstance(); + input.set(2026, Calendar.MARCH, 15, 14, 30, 45); + input.set(Calendar.MILLISECOND, 500); + + Date result = calendarUtil.getStartOfDay(input.getTime()); + + Calendar cal = toCalendar(result); + assertEquals(2026, cal.get(Calendar.YEAR)); + assertEquals(Calendar.MARCH, cal.get(Calendar.MONTH)); + assertEquals(15, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(0, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(0, cal.get(Calendar.MINUTE)); + assertEquals(0, cal.get(Calendar.SECOND)); + assertEquals(0, cal.get(Calendar.MILLISECOND)); + } + + @Test + void getStartOfDay_alreadyMidnight_returnsSameTime() { + Calendar input = Calendar.getInstance(); + input.set(2026, Calendar.JANUARY, 1, 0, 0, 0); + input.set(Calendar.MILLISECOND, 0); + + Date result = calendarUtil.getStartOfDay(input.getTime()); + + Calendar cal = toCalendar(result); + assertEquals(0, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(0, cal.get(Calendar.MINUTE)); + assertEquals(0, cal.get(Calendar.SECOND)); + assertEquals(0, cal.get(Calendar.MILLISECOND)); + } + + @Test + void getStartOfDay_endOfDay_returnsStartOfSameDay() { + Calendar input = Calendar.getInstance(); + input.set(2026, Calendar.JUNE, 20, 23, 59, 59); + input.set(Calendar.MILLISECOND, 999); + + Date result = calendarUtil.getStartOfDay(input.getTime()); + + Calendar cal = toCalendar(result); + assertEquals(20, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(0, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(0, cal.get(Calendar.MINUTE)); + assertEquals(0, cal.get(Calendar.SECOND)); + assertEquals(0, cal.get(Calendar.MILLISECOND)); + } + + // --- getEndOfDay --- + + @Test + void getEndOfDay_returnsDateAt235959999() { + Calendar input = Calendar.getInstance(); + input.set(2026, Calendar.MARCH, 15, 10, 0, 0); + input.set(Calendar.MILLISECOND, 0); + + Date result = calendarUtil.getEndOfDay(input.getTime()); + + Calendar cal = toCalendar(result); + assertEquals(2026, cal.get(Calendar.YEAR)); + assertEquals(Calendar.MARCH, cal.get(Calendar.MONTH)); + assertEquals(15, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(23, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(59, cal.get(Calendar.MINUTE)); + assertEquals(59, cal.get(Calendar.SECOND)); + assertEquals(999, cal.get(Calendar.MILLISECOND)); + } + + @Test + void getEndOfDay_fromMidnight_returnsEndOfSameDay() { + Calendar input = Calendar.getInstance(); + input.set(2026, Calendar.JANUARY, 1, 0, 0, 0); + input.set(Calendar.MILLISECOND, 0); + + Date result = calendarUtil.getEndOfDay(input.getTime()); + + Calendar cal = toCalendar(result); + assertEquals(1, cal.get(Calendar.DAY_OF_MONTH)); + assertEquals(23, cal.get(Calendar.HOUR_OF_DAY)); + assertEquals(59, cal.get(Calendar.MINUTE)); + assertEquals(59, cal.get(Calendar.SECOND)); + assertEquals(999, cal.get(Calendar.MILLISECOND)); + } + + // --- startOfDay / endOfDay consistency --- + + @Test + void startOfDay_isBeforeEndOfDay() { + Date now = new Date(); + + Date start = calendarUtil.getStartOfDay(now); + Date end = calendarUtil.getEndOfDay(now); + + assertTrue(start.before(end)); + } + + @Test + void startAndEnd_preserveSameDay() { + Calendar input = Calendar.getInstance(); + input.set(2026, Calendar.JULY, 4, 12, 0, 0); + + Date start = calendarUtil.getStartOfDay(input.getTime()); + Date end = calendarUtil.getEndOfDay(input.getTime()); + + Calendar startCal = toCalendar(start); + Calendar endCal = toCalendar(end); + assertEquals(startCal.get(Calendar.YEAR), endCal.get(Calendar.YEAR)); + assertEquals(startCal.get(Calendar.MONTH), endCal.get(Calendar.MONTH)); + assertEquals(startCal.get(Calendar.DAY_OF_MONTH), endCal.get(Calendar.DAY_OF_MONTH)); + } + + private Calendar toCalendar(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal; + } +} diff --git a/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/EvaluationUtilTest.java b/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/EvaluationUtilTest.java new file mode 100644 index 0000000..1d78798 --- /dev/null +++ b/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/EvaluationUtilTest.java @@ -0,0 +1,60 @@ +package marketing.heyday.hartmann.fotodocumentation.core.utils; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * + *

Copyright: Copyright (c) 2024

+ *

Company: heyday Marketing GmbH

+ * @author Patrick Verboom + * @version 1.0 + * + * created: 3 Feb 2026 + */ +class EvaluationUtilTest { + + private EvaluationUtil evaluationUtil; + + @BeforeEach + void setUp() { + evaluationUtil = new EvaluationUtil(); + } + + @Test + void isValid_null_returnsTrue() { + assertTrue(evaluationUtil.isValid(null)); + } + + @Test + void isValid_zero_returnsTrue() { + assertTrue(evaluationUtil.isValid(0)); + } + + @Test + void isValid_negativeValue_returnsTrue() { + assertTrue(evaluationUtil.isValid(-1)); + } + + @Test + void isValid_one_returnsFalse() { + assertFalse(evaluationUtil.isValid(1)); + } + + @Test + void isValid_two_returnsTrue() { + assertTrue(evaluationUtil.isValid(2)); + } + + @Test + void isValid_three_returnsTrue() { + assertTrue(evaluationUtil.isValid(3)); + } + + @Test + void isValid_largeValue_returnsTrue() { + assertTrue(evaluationUtil.isValid(100)); + } +} diff --git a/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/ImageUtilTest.java b/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/ImageUtilTest.java new file mode 100644 index 0000000..dfc5805 --- /dev/null +++ b/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/ImageUtilTest.java @@ -0,0 +1,240 @@ +package marketing.heyday.hartmann.fotodocumentation.core.utils; + +import static org.junit.jupiter.api.Assertions.*; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; + +import javax.imageio.ImageIO; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * + *

Copyright: Copyright (c) 2024

+ *

Company: heyday Marketing GmbH

+ * @author Patrick Verboom + * @version 1.0 + * + * created: 3 Feb 2026 + */ +class ImageUtilTest { + + private ImageUtil imageUtil; + + @BeforeEach + void setUp() { + imageUtil = new ImageUtil(); + } + + // --- Size 1: original --- + + @Test + void getImage_size1_returnsOriginalBytes() { + String base64 = createTestImageBase64(800, 600); + byte[] original = Base64.getDecoder().decode(base64); + + byte[] result = imageUtil.getImage(base64, 1); + + assertArrayEquals(original, result); + } + + @Test + void getImage_size1_largeImage_returnsOriginalBytes() { + String base64 = createTestImageBase64(2000, 1500); + byte[] original = Base64.getDecoder().decode(base64); + + byte[] result = imageUtil.getImage(base64, 1); + + assertArrayEquals(original, result); + } + + // --- Size 2: normal (web, max 1200px) --- + + @Test + void getImage_size2_largeImage_resizesToMaxWidth1200() throws IOException { + String base64 = createTestImageBase64(2400, 1600); + + byte[] result = imageUtil.getImage(base64, 2); + + BufferedImage resized = ImageIO.read(new ByteArrayInputStream(result)); + assertEquals(1200, resized.getWidth()); + } + + @Test + void getImage_size2_largeImage_preservesAspectRatio() throws IOException { + String base64 = createTestImageBase64(2400, 1600); + + byte[] result = imageUtil.getImage(base64, 2); + + BufferedImage resized = ImageIO.read(new ByteArrayInputStream(result)); + assertEquals(1200, resized.getWidth()); + assertEquals(800, resized.getHeight()); + } + + @Test + void getImage_size2_largeImage_resultIsSmallerThanOriginal() { + String base64 = createNoisyImageBase64(2400, 1600); + byte[] original = Base64.getDecoder().decode(base64); + + byte[] result = imageUtil.getImage(base64, 2); + + assertTrue(result.length < original.length); + } + + @Test + void getImage_size2_smallImage_returnsOriginal() { + String base64 = createTestImageBase64(800, 600); + byte[] original = Base64.getDecoder().decode(base64); + + byte[] result = imageUtil.getImage(base64, 2); + + assertArrayEquals(original, result); + } + + @Test + void getImage_size2_exactMaxWidth_returnsOriginal() { + String base64 = createTestImageBase64(1200, 900); + byte[] original = Base64.getDecoder().decode(base64); + + byte[] result = imageUtil.getImage(base64, 2); + + assertArrayEquals(original, result); + } + + // --- Size 3: thumbnail (max 200px) --- + + @Test + void getImage_size3_largeImage_resizesToMaxWidth200() throws IOException { + String base64 = createTestImageBase64(2400, 1600); + + byte[] result = imageUtil.getImage(base64, 3); + + BufferedImage resized = ImageIO.read(new ByteArrayInputStream(result)); + assertEquals(200, resized.getWidth()); + } + + @Test + void getImage_size3_largeImage_preservesAspectRatio() throws IOException { + String base64 = createTestImageBase64(2400, 1600); + + byte[] result = imageUtil.getImage(base64, 3); + + BufferedImage resized = ImageIO.read(new ByteArrayInputStream(result)); + assertEquals(200, resized.getWidth()); + assertEquals(133, resized.getHeight()); + } + + @Test + void getImage_size3_largeImage_resultIsSmallerThanNormal() { + String base64 = createTestImageBase64(2400, 1600); + + byte[] normal = imageUtil.getImage(base64, 2); + byte[] thumbnail = imageUtil.getImage(base64, 3); + + assertTrue(thumbnail.length < normal.length); + } + + @Test + void getImage_size3_smallImage_returnsOriginal() { + String base64 = createTestImageBase64(150, 100); + byte[] original = Base64.getDecoder().decode(base64); + + byte[] result = imageUtil.getImage(base64, 3); + + assertArrayEquals(original, result); + } + + // --- Default size --- + + @Test + void getImage_unknownSize_returnsOriginalBytes() { + String base64 = createTestImageBase64(800, 600); + byte[] original = Base64.getDecoder().decode(base64); + + byte[] result = imageUtil.getImage(base64, 99); + + assertArrayEquals(original, result); + } + + // --- Output format --- + + @Test + void getImage_size2_outputIsJpeg() throws IOException { + String base64 = createTestImageBase64(2400, 1600); + + byte[] result = imageUtil.getImage(base64, 2); + + // JPEG files start with FF D8 FF + assertEquals((byte) 0xFF, result[0]); + assertEquals((byte) 0xD8, result[1]); + assertEquals((byte) 0xFF, result[2]); + } + + @Test + void getImage_size3_outputIsJpeg() throws IOException { + String base64 = createTestImageBase64(2400, 1600); + + byte[] result = imageUtil.getImage(base64, 3); + + assertEquals((byte) 0xFF, result[0]); + assertEquals((byte) 0xD8, result[1]); + assertEquals((byte) 0xFF, result[2]); + } + + // --- Edge cases --- + + @Test + void getImage_size2_squareImage_preservesAspectRatio() throws IOException { + String base64 = createTestImageBase64(2000, 2000); + + byte[] result = imageUtil.getImage(base64, 2); + + BufferedImage resized = ImageIO.read(new ByteArrayInputStream(result)); + assertEquals(1200, resized.getWidth()); + assertEquals(1200, resized.getHeight()); + } + + @Test + void getImage_size2_veryWideImage_preservesAspectRatio() throws IOException { + String base64 = createTestImageBase64(4000, 500); + + byte[] result = imageUtil.getImage(base64, 2); + + BufferedImage resized = ImageIO.read(new ByteArrayInputStream(result)); + assertEquals(1200, resized.getWidth()); + assertEquals(150, resized.getHeight()); + } + + private String createTestImageBase64(int width, int height) { + try { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "png", baos); + return Base64.getEncoder().encodeToString(baos.toByteArray()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private String createNoisyImageBase64(int width, int height) { + try { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + java.util.Random random = new java.util.Random(42); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + image.setRGB(x, y, random.nextInt(0xFFFFFF)); + } + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "png", baos); + return Base64.getEncoder().encodeToString(baos.toByteArray()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/PdfUtilsTest.java b/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/PdfUtilsTest.java index 38d712d..6ddb059 100644 --- a/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/PdfUtilsTest.java +++ b/hartmann-foto-documentation-app/src/test/java/marketing/heyday/hartmann/fotodocumentation/core/utils/PdfUtilsTest.java @@ -198,7 +198,7 @@ class PdfUtilsTest { } @Test - void createPdf_nullEvaluation_doesNotThrow() throws IOException { + void createPdf_nullEvaluation_doesNotThrow() { Picture picture = new Picture.Builder() .pictureDate(new Date()) .comment("Test") diff --git a/hartmann-foto-documentation-docker/src/test/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerResourceTest.java b/hartmann-foto-documentation-docker/src/test/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerResourceTest.java index dc16cd6..b72073d 100644 --- a/hartmann-foto-documentation-docker/src/test/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerResourceTest.java +++ b/hartmann-foto-documentation-docker/src/test/java/marketing/heyday/hartmann/fotodocumentation/rest/CustomerResourceTest.java @@ -123,7 +123,7 @@ public class CustomerResourceTest extends AbstractRestTest { String authorization = getAuthorization(); LOG.info("authorization: " + authorization); - String path = deploymentURL + PATH+ "?query=12.01.2026"; + String path = deploymentURL + PATH + "?query=12.01.2026"; Request request = Request.Get(path).addHeader("Accept", "application/json; charset=utf-8") .addHeader("Authorization", authorization); @@ -135,7 +135,7 @@ public class CustomerResourceTest extends AbstractRestTest { String expected = fileToString(BASE_DOWNLOAD + "doGetAllQueryDate.json"); jsonAssert(expected, text); } - + @Test @Order(1) public void doGetAllQueryDate2() throws IOException { @@ -144,7 +144,7 @@ public class CustomerResourceTest extends AbstractRestTest { String authorization = getAuthorization(); LOG.info("authorization: " + authorization); String query = URLEncoder.encode("12 Januar 2026", Charset.forName("utf-8")); - String path = deploymentURL + PATH+ "?query="+ query; + String path = deploymentURL + PATH + "?query=" + query; Request request = Request.Get(path).addHeader("Accept", "application/json; charset=utf-8") .addHeader("Authorization", authorization); @@ -156,7 +156,7 @@ public class CustomerResourceTest extends AbstractRestTest { String expected = fileToString(BASE_DOWNLOAD + "doGetAllQueryDate.json"); jsonAssert(expected, text); } - + @Test @Order(1) public void doGetAllQueryDate3() throws IOException { @@ -165,7 +165,7 @@ public class CustomerResourceTest extends AbstractRestTest { String authorization = getAuthorization(); LOG.info("authorization: " + authorization); String query = URLEncoder.encode("12. Januar 2026", Charset.forName("utf-8")); - String path = deploymentURL + PATH+ "?query="+ query; + String path = deploymentURL + PATH + "?query=" + query; Request request = Request.Get(path).addHeader("Accept", "application/json; charset=utf-8") .addHeader("Authorization", authorization); @@ -197,8 +197,7 @@ public class CustomerResourceTest extends AbstractRestTest { String expected = fileToString(BASE_DOWNLOAD + "doGetCustomer.json"); jsonAssert(expected, text); } - - + @Test @Order(1) public void doDownload() throws IOException { @@ -213,10 +212,24 @@ public class CustomerResourceTest extends AbstractRestTest { HttpResponse httpResponse = executeRequest(request); int code = httpResponse.getStatusLine().getStatusCode(); assertEquals(200, code); - byte[] text = getResponse(httpResponse); writeFile(text, "doDownload.pdf"); - + } + + @Test + @Order(1) + public void doDownloadNotExist() throws IOException { + LOG.info("doDownloadNotExist"); + + String authorization = getAuthorization(); + LOG.info("authorization: " + authorization); + String path = deploymentURL + PATH + "/export/9999"; + Request request = Request.Get(path).addHeader("Accept", "application/pdf") + .addHeader("Authorization", authorization); + + HttpResponse httpResponse = executeRequest(request); + int code = httpResponse.getStatusLine().getStatusCode(); + assertEquals(404, code); } } diff --git a/hartmann-foto-documentation-docker/src/test/java/marketing/heyday/hartmann/fotodocumentation/rest/PictureResourceTest.java b/hartmann-foto-documentation-docker/src/test/java/marketing/heyday/hartmann/fotodocumentation/rest/PictureResourceTest.java index fe27296..cb0073f 100644 --- a/hartmann-foto-documentation-docker/src/test/java/marketing/heyday/hartmann/fotodocumentation/rest/PictureResourceTest.java +++ b/hartmann-foto-documentation-docker/src/test/java/marketing/heyday/hartmann/fotodocumentation/rest/PictureResourceTest.java @@ -1,6 +1,6 @@ package marketing.heyday.hartmann.fotodocumentation.rest; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.*; import java.io.IOException; @@ -75,8 +75,6 @@ public class PictureResourceTest extends AbstractRestTest { LOG.info("doEvaluation"); assertEquals(0, getCount("select count(*) from picture where picture_id = 1 and evaluation = 3")); - - String path = deploymentURL + PATH + "/evaluation/1?evaluation=3"; Request request = Request.Put(path).addHeader("Accept", "application/json; charset=utf-8") @@ -102,4 +100,82 @@ public class PictureResourceTest extends AbstractRestTest { int code = httpResponse.getStatusLine().getStatusCode(); assertEquals(404, code); } + + @Test + @Order(1) + public void doEvaluationWrongValue() throws IOException { + LOG.info("doEvaluationWrongValue"); + + String path = deploymentURL + PATH + "/evaluation/1?evaluation=4"; + Request request = Request.Put(path).addHeader("Accept", "application/json; charset=utf-8") + .addHeader("Authorization", getAuthorization()); + + HttpResponse httpResponse = executeRequest(request); + int code = httpResponse.getStatusLine().getStatusCode(); + assertEquals(400, code); + } + + @Test + @Order(1) + public void doEvaluationWrongValue2() throws IOException { + LOG.info("doEvaluationWrongValue2"); + + String path = deploymentURL + PATH + "/evaluation/1?evaluation=0"; + Request request = Request.Put(path).addHeader("Accept", "application/json; charset=utf-8") + .addHeader("Authorization", getAuthorization()); + + HttpResponse httpResponse = executeRequest(request); + int code = httpResponse.getStatusLine().getStatusCode(); + assertEquals(400, code); + } + + @Test + @Order(1) + public void doEvaluationNoValue() throws IOException { + LOG.info("doEvaluationNoValue"); + + String path = deploymentURL + PATH + "/evaluation/1"; + Request request = Request.Put(path).addHeader("Accept", "application/json; charset=utf-8") + .addHeader("Authorization", getAuthorization()); + + HttpResponse httpResponse = executeRequest(request); + int code = httpResponse.getStatusLine().getStatusCode(); + assertEquals(400, code); + } + + @Test + @Order(1) + public void doGetPicture() throws IOException { + LOG.info("doGetPicture"); + + String authorization = getAuthorization(); + LOG.info("authorization: " + authorization); + String path = deploymentURL + PATH + "/image/1?size=1"; + Request request = Request.Get(path).addHeader("Accept", "image/jpg") + .addHeader("Authorization", authorization); + + HttpResponse httpResponse = executeRequest(request); + int code = httpResponse.getStatusLine().getStatusCode(); + assertEquals(200, code); + + byte[] file = getResponse(httpResponse); + assertTrue(file.length > 0); + writeFile(file, "doGetPicture.jpg"); + } + + @Test + @Order(1) + public void doGetPictureNotFound() throws IOException { + LOG.info("doGetPicture"); + + String authorization = getAuthorization(); + LOG.info("authorization: " + authorization); + String path = deploymentURL + PATH + "/image/9999?size=1"; + Request request = Request.Get(path).addHeader("Accept", "image/jpg") + .addHeader("Authorization", authorization); + + HttpResponse httpResponse = executeRequest(request); + int code = httpResponse.getStatusLine().getStatusCode(); + assertEquals(404, code); + } }