Skip to content

Commit

Permalink
AYS-550 | NoSpacesAround Annotation Has Been Created to Check Leadi…
Browse files Browse the repository at this point in the history
…ng and Trailing Spaces (#404)
  • Loading branch information
egehanasal authored Dec 8, 2024
1 parent b146de0 commit 83312d5
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.Getter;
import lombok.Setter;
import org.ays.common.util.validation.NoSpecialCharacters;
import org.ays.common.util.validation.NoSpacesAround;

/**
* Represents a request to register a new admin application. The request includes fields for the required
Expand All @@ -26,6 +27,7 @@ public class AdminRegistrationApplicationCreateRequest {
@NotBlank
@Size(min = 40, max = 512)
@NoSpecialCharacters
@NoSpacesAround
private String reason;

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import org.ays.common.util.validation.NoSpacesAround;

/**
* Represents a request to reject a new admin application. The request includes fields for the required application reject reason.
Expand All @@ -17,6 +18,7 @@ public class AdminRegistrationApplicationRejectRequest {
*/
@NotBlank
@Size(min = 40, max = 512)
@NoSpacesAround
private String rejectReason;

}
39 changes: 39 additions & 0 deletions src/main/java/org/ays/common/util/validation/NoSpacesAround.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.ays.common.util.validation;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to validate a text using {@link NoSpacesAroundValidator}.
*/
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NoSpacesAroundValidator.class)
public @interface NoSpacesAround {

/**
* Returns the error message when the text is not valid.
*
* @return the error message
*/
String message() default "cannot start or end with space";

/**
* Returns the validation groups to which this constraint belongs.
*
* @return the validation groups
*/
Class<?>[] groups() default {};

/**
* Returns the payload associated to this constraint.
*
* @return the payload
*/
Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.ays.common.util.validation;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.util.StringUtils;

/**
* A custom validator implementation for the {@link NoSpacesAround} annotation.
* Validates whether the provided text does not have
* trailing or leading spaces.
*/
class NoSpacesAroundValidator implements ConstraintValidator<NoSpacesAround, String> {

@Override
public boolean isValid(String text, ConstraintValidatorContext constraintValidatorContext) {

if (!StringUtils.hasText(text)) {
return true;
}

return !(text.startsWith(" ") || text.endsWith(" "));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,6 @@ public boolean isValid(String value, ConstraintValidatorContext constraintValida
return true;
}

boolean startsOrEndsWithSpace = value.matches("^\\s.*|.*\\s$");

if (startsOrEndsWithSpace) {
constraintValidatorContext.disableDefaultConstraintViolation();
constraintValidatorContext.buildConstraintViolationWithTemplate("cannot start or end with space")
.addConstraintViolation();
return false;
}

boolean containsOnlyDigits = value.matches("^\\d+$");

if (containsOnlyDigits) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import org.ays.common.util.validation.NoSpacesAround;
import org.ays.emergency_application.model.enums.EmergencyEvacuationApplicationStatus;
import org.hibernate.validator.constraints.Range;

Expand Down Expand Up @@ -43,6 +44,7 @@ public class EmergencyEvacuationApplicationUpdateRequest {
* The notes can have a maximum length of 1000 characters.
*/
@Size(max = 1000)
@NoSpacesAround
private String notes;

}
Original file line number Diff line number Diff line change
Expand Up @@ -781,4 +781,50 @@ void givenValidAdminRegisterApplicationRejectRequest_whenUnauthorizedForRejectin
.reject(Mockito.eq(mockId), Mockito.any(AdminRegistrationApplicationRejectRequest.class));
}

@ParameterizedTest
@ValueSource(strings = {
"",
" ",
"less than 40",
"""
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor.
Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
Donec qudam felis, ultricies nec, pellentesque eu, pretscsxwium quis, sem. Nulla consequat massa quis
enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut,
imperdiet a, venenatdskjvndshjcndsis vitae, justo. Nullam dictum felis eu pedde mollis pretium. Integer tincidunt.
Cras dapibus. Vivdamus ewl
""",
" spaceAtTheBeginning",
"spaceAtTheEnd ",
" both ",
" justAString "
})
void givenInvalidAdminRegisterApplicationRejectRequest_whenRejectingAdminRegisterApplication_thenReturnValidationError(String rejectReason) throws Exception {

// Given
String mockId = "4d04bd1e-6318-43ba-ab40-57efb8afc918";
AdminRegistrationApplicationRejectRequest mockRequest = new AdminRegistrationApplicationRejectRequestBuilder()
.withValidValues()
.withRejectReason(rejectReason)
.build();

// Then
String endpoint = BASE_PATH.concat("/admin-registration-application/").concat(mockId).concat("/reject");
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockUserToken.getAccessToken(), mockRequest);

AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.VALIDATION_ERROR;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
.isBadRequest())
.andExpect(AysMockResultMatchersBuilders.subErrors()
.isNotEmpty());

// Verify
Mockito.verify(adminRegistrationApplicationService, Mockito.never())
.reject(Mockito.anyString(),
Mockito.any(AdminRegistrationApplicationRejectRequest.class));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,7 @@ void givenInvalidEmergencyEvacuationApplicationListRequest_whenReferenceNumberNo
".,..,.,.,.,.,,.,.,.,.,.,.,.,.,..,.,.,,.,.,.,",
"t",
"151201485621548562154851458614125461254125412",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam In hac habitasse platea dictumst. Nullam in turpis at nunc ultrices.",
" spaceAtTheBeginning",
"spaceAtTheEnd ",
" both ",
" justAString "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam In hac habitasse platea dictumst. Nullam in turpis at nunc ultrices."
})
void givenInvalidEmergencyEvacuationApplicationListRequest_whenSourceCityNotValid_thenReturnValidationError(String sourceCity) throws Exception {

Expand Down Expand Up @@ -173,11 +169,7 @@ void givenInvalidEmergencyEvacuationApplicationListRequest_whenSourceCityNotVali
".,..,.,.,.,.,,.,.,.,.,.,.,.,.,..,.,.,,.,.,.,",
"t",
"151201485621548562154851458614125461254125412",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam In hac habitasse platea dictumst. Nullam in turpis at nunc ultrices.",
" spaceAtTheBeginning",
"spaceAtTheEnd ",
" both ",
" justAString ",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam In hac habitasse platea dictumst. Nullam in turpis at nunc ultrices."
})
void givenInvalidEmergencyEvacuationApplicationListRequest_whenSourceDistrictNotValid_thenReturnValidationError(String sourceDistrict) throws Exception {

Expand Down Expand Up @@ -245,11 +237,7 @@ void givenInvalidEmergencyEvacuationApplicationListRequest_whenSeatingCountNotVa
".,..,.,.,.,.,,.,.,.,.,.,.,.,.,..,.,.,,.,.,.,",
"t",
"151201485621548562154851458614125461254125412",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam In hac habitasse platea dictumst. Nullam in turpis at nunc ultrices.",
" spaceAtTheBeginning",
"spaceAtTheEnd ",
" both ",
" justAString ",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam In hac habitasse platea dictumst. Nullam in turpis at nunc ultrices."
})
void givenInvalidEmergencyEvacuationApplicationListRequest_whenTargetCityNotValid_thenReturnValidationError(String targetCity) throws Exception {

Expand Down Expand Up @@ -285,11 +273,7 @@ void givenInvalidEmergencyEvacuationApplicationListRequest_whenTargetCityNotVali
".,..,.,.,.,.,,.,.,.,.,.,.,.,.,..,.,.,,.,.,.,",
"t",
"151201485621548562154851458614125461254125412",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam In hac habitasse platea dictumst. Nullam in turpis at nunc ultrices.",
" spaceAtTheBeginning",
"spaceAtTheEnd ",
" both ",
" justAString ",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam In hac habitasse platea dictumst. Nullam in turpis at nunc ultrices."
})
void givenInvalidEmergencyEvacuationApplicationListRequest_whenTargetDistrictNotValid_thenReturnValidationError(String targetDistrict) throws Exception {

Expand Down Expand Up @@ -1124,7 +1108,11 @@ void givenValidIdAndUpdateRequest_whenStatusDoesNotValid_thenReturnValidationErr
"""
Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.
The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.
"""
""",
" spaceAtTheBeginning",
"spaceAtTheEnd ",
" both ",
" justAString "
})
void givenValidIdAndUpdateRequest_whenNotesDoesNotValid_thenReturnValidationError(String mockNotes) throws Exception {
// Given
Expand Down

0 comments on commit 83312d5

Please sign in to comment.