Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package io.spring.api.exception;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import javax.validation.metadata.ConstraintDescriptor;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.context.request.WebRequest;

public class CustomizeExceptionHandlerTest {

private CustomizeExceptionHandler handler;
private WebRequest webRequest;

@BeforeEach
public void setUp() {
handler = new CustomizeExceptionHandler();
webRequest = mock(WebRequest.class);
}

@Test
public void should_handle_invalid_request_exception() {
Errors errors = new BeanPropertyBindingResult(new Object(), "testObject");
((BeanPropertyBindingResult) errors)
.addError(new FieldError("testObject", "fieldName", "must not be blank"));

InvalidRequestException exception = new InvalidRequestException(errors);

ResponseEntity<Object> response = handler.handleInvalidRequest(exception, webRequest);

Assertions.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, response.getStatusCode());
Assertions.assertNotNull(response.getBody());
}

@Test
public void should_handle_invalid_request_with_multiple_field_errors() {
Errors errors = new BeanPropertyBindingResult(new Object(), "testObject");
((BeanPropertyBindingResult) errors)
.addError(new FieldError("testObject", "email", "must be valid email"));
((BeanPropertyBindingResult) errors)
.addError(new FieldError("testObject", "username", "must not be blank"));

InvalidRequestException exception = new InvalidRequestException(errors);

ResponseEntity<Object> response = handler.handleInvalidRequest(exception, webRequest);

Assertions.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, response.getStatusCode());
}

@Test
@SuppressWarnings("unchecked")
public void should_handle_invalid_authentication_exception() {
InvalidAuthenticationException exception = new InvalidAuthenticationException();

ResponseEntity<Object> response = handler.handleInvalidAuthentication(exception, webRequest);

Assertions.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, response.getStatusCode());
Assertions.assertNotNull(response.getBody());
Map<String, Object> body = (Map<String, Object>) response.getBody();
Assertions.assertEquals("invalid email or password", body.get("message"));
}

@Test
@SuppressWarnings("unchecked")
public void should_handle_constraint_violation_exception_simple_path() {
ConstraintViolation<?> violation = mock(ConstraintViolation.class);
Path path = mock(Path.class);
when(path.toString()).thenReturn("fieldName");
when(violation.getPropertyPath()).thenReturn(path);
when(violation.getMessage()).thenReturn("must not be blank");
when(violation.getRootBeanClass()).thenReturn((Class) Object.class);

ConstraintDescriptor<?> descriptor = mock(ConstraintDescriptor.class);
Annotation annotation = mock(Annotation.class);
when(annotation.annotationType()).thenReturn((Class) Override.class);
when(descriptor.getAnnotation()).thenReturn(annotation);
doReturn(descriptor).when(violation).getConstraintDescriptor();

Set<ConstraintViolation<?>> violations = new HashSet<>();
violations.add(violation);
ConstraintViolationException ex = new ConstraintViolationException(violations);

ErrorResource result = handler.handleConstraintViolation(ex, webRequest);

Assertions.assertNotNull(result);
List<FieldErrorResource> fieldErrors = result.getFieldErrors();
Assertions.assertEquals(1, fieldErrors.size());
Assertions.assertEquals("fieldName", fieldErrors.get(0).getField());
Assertions.assertEquals("must not be blank", fieldErrors.get(0).getMessage());
}

@Test
@SuppressWarnings("unchecked")
public void should_handle_constraint_violation_exception_nested_path() {
ConstraintViolation<?> violation = mock(ConstraintViolation.class);
Path path = mock(Path.class);
when(path.toString()).thenReturn("createArticle.newArticleParam.title");
when(violation.getPropertyPath()).thenReturn(path);
when(violation.getMessage()).thenReturn("can't be empty");
when(violation.getRootBeanClass()).thenReturn((Class) Object.class);

ConstraintDescriptor<?> descriptor = mock(ConstraintDescriptor.class);
Annotation annotation = mock(Annotation.class);
when(annotation.annotationType()).thenReturn((Class) Override.class);
when(descriptor.getAnnotation()).thenReturn(annotation);
doReturn(descriptor).when(violation).getConstraintDescriptor();

Set<ConstraintViolation<?>> violations = new HashSet<>();
violations.add(violation);
ConstraintViolationException ex = new ConstraintViolationException(violations);

ErrorResource result = handler.handleConstraintViolation(ex, webRequest);

Assertions.assertNotNull(result);
List<FieldErrorResource> fieldErrors = result.getFieldErrors();
Assertions.assertEquals(1, fieldErrors.size());
Assertions.assertEquals("title", fieldErrors.get(0).getField());
}

@Test
@SuppressWarnings("unchecked")
public void should_handle_constraint_violation_with_multiple_violations() {
ConstraintViolation<?> violation1 = mock(ConstraintViolation.class);
Path path1 = mock(Path.class);
when(path1.toString()).thenReturn("method.param.email");
when(violation1.getPropertyPath()).thenReturn(path1);
when(violation1.getMessage()).thenReturn("invalid email");
when(violation1.getRootBeanClass()).thenReturn((Class) Object.class);

ConstraintDescriptor<?> descriptor1 = mock(ConstraintDescriptor.class);
Annotation annotation1 = mock(Annotation.class);
when(annotation1.annotationType()).thenReturn((Class) Override.class);
when(descriptor1.getAnnotation()).thenReturn(annotation1);
doReturn(descriptor1).when(violation1).getConstraintDescriptor();

ConstraintViolation<?> violation2 = mock(ConstraintViolation.class);
Path path2 = mock(Path.class);
when(path2.toString()).thenReturn("method.param.username");
when(violation2.getPropertyPath()).thenReturn(path2);
when(violation2.getMessage()).thenReturn("already taken");
when(violation2.getRootBeanClass()).thenReturn((Class) Object.class);

ConstraintDescriptor<?> descriptor2 = mock(ConstraintDescriptor.class);
Annotation annotation2 = mock(Annotation.class);
when(annotation2.annotationType()).thenReturn((Class) Override.class);
when(descriptor2.getAnnotation()).thenReturn(annotation2);
doReturn(descriptor2).when(violation2).getConstraintDescriptor();

Set<ConstraintViolation<?>> violations = new HashSet<>();
violations.add(violation1);
violations.add(violation2);
ConstraintViolationException ex = new ConstraintViolationException(violations);

ErrorResource result = handler.handleConstraintViolation(ex, webRequest);

Assertions.assertNotNull(result);
Assertions.assertEquals(2, result.getFieldErrors().size());
}

@Test
public void should_handle_invalid_request_with_no_field_errors() {
Errors errors = new BeanPropertyBindingResult(new Object(), "testObject");

InvalidRequestException exception = new InvalidRequestException(errors);

ResponseEntity<Object> response = handler.handleInvalidRequest(exception, webRequest);

Assertions.assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, response.getStatusCode());
}
}
148 changes: 148 additions & 0 deletions src/test/java/io/spring/application/CursorPagerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package io.spring.application;

import io.spring.application.CursorPager.Direction;
import io.spring.application.data.CommentData;
import io.spring.application.data.ProfileData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class CursorPagerTest {

private ProfileData profileData = new ProfileData("id", "user", "bio", "image", false);

private CommentData createComment(String id, DateTime createdAt) {
return new CommentData(id, "body", "articleId", createdAt, createdAt, profileData);
}

@Test
public void should_set_next_true_when_has_extra_in_next_direction() {
DateTime now = new DateTime();
CommentData comment1 = createComment("c1", now);
CommentData comment2 = createComment("c2", now.plusMinutes(1));

CursorPager<CommentData> pager =
new CursorPager<>(Arrays.asList(comment1, comment2), Direction.NEXT, true);

Assertions.assertTrue(pager.hasNext());
Assertions.assertFalse(pager.hasPrevious());
}

@Test
public void should_set_next_false_when_no_extra_in_next_direction() {
DateTime now = new DateTime();
CommentData comment1 = createComment("c1", now);

CursorPager<CommentData> pager =
new CursorPager<>(Arrays.asList(comment1), Direction.NEXT, false);

Assertions.assertFalse(pager.hasNext());
Assertions.assertFalse(pager.hasPrevious());
}

@Test
public void should_set_previous_true_when_has_extra_in_prev_direction() {
DateTime now = new DateTime();
CommentData comment1 = createComment("c1", now);

CursorPager<CommentData> pager =
new CursorPager<>(Arrays.asList(comment1), Direction.PREV, true);

Assertions.assertFalse(pager.hasNext());
Assertions.assertTrue(pager.hasPrevious());
}

@Test
public void should_set_previous_false_when_no_extra_in_prev_direction() {
DateTime now = new DateTime();
CommentData comment1 = createComment("c1", now);

CursorPager<CommentData> pager =
new CursorPager<>(Arrays.asList(comment1), Direction.PREV, false);

Assertions.assertFalse(pager.hasNext());
Assertions.assertFalse(pager.hasPrevious());
}

@Test
public void should_return_null_start_cursor_when_data_empty() {
CursorPager<CommentData> pager =
new CursorPager<>(Collections.emptyList(), Direction.NEXT, false);

Assertions.assertNull(pager.getStartCursor());
}

@Test
public void should_return_null_end_cursor_when_data_empty() {
CursorPager<CommentData> pager =
new CursorPager<>(Collections.emptyList(), Direction.NEXT, false);

Assertions.assertNull(pager.getEndCursor());
}

@Test
public void should_return_start_cursor_from_first_element() {
DateTime now = new DateTime();
CommentData comment1 = createComment("c1", now);
CommentData comment2 = createComment("c2", now.plusMinutes(1));

CursorPager<CommentData> pager =
new CursorPager<>(Arrays.asList(comment1, comment2), Direction.NEXT, false);

Assertions.assertNotNull(pager.getStartCursor());
Assertions.assertEquals(String.valueOf(now.getMillis()), pager.getStartCursor().toString());
}

@Test
public void should_return_end_cursor_from_last_element() {
DateTime now = new DateTime();
DateTime later = now.plusMinutes(5);
CommentData comment1 = createComment("c1", now);
CommentData comment2 = createComment("c2", later);

CursorPager<CommentData> pager =
new CursorPager<>(Arrays.asList(comment1, comment2), Direction.NEXT, false);

Assertions.assertNotNull(pager.getEndCursor());
Assertions.assertEquals(String.valueOf(later.getMillis()), pager.getEndCursor().toString());
}

@Test
public void should_return_same_cursor_for_single_element() {
DateTime now = new DateTime();
CommentData comment1 = createComment("c1", now);

CursorPager<CommentData> pager =
new CursorPager<>(Arrays.asList(comment1), Direction.NEXT, false);

Assertions.assertEquals(pager.getStartCursor().toString(), pager.getEndCursor().toString());
}

@Test
public void should_get_data_list() {
DateTime now = new DateTime();
CommentData comment1 = createComment("c1", now);
CommentData comment2 = createComment("c2", now.plusMinutes(1));

CursorPager<CommentData> pager =
new CursorPager<>(Arrays.asList(comment1, comment2), Direction.NEXT, false);

Assertions.assertEquals(2, pager.getData().size());
Assertions.assertEquals("c1", pager.getData().get(0).getId());
Assertions.assertEquals("c2", pager.getData().get(1).getId());
}

@Test
public void should_handle_empty_list_with_prev_direction() {
CursorPager<CommentData> pager = new CursorPager<>(new ArrayList<>(), Direction.PREV, false);

Assertions.assertTrue(pager.getData().isEmpty());
Assertions.assertFalse(pager.hasNext());
Assertions.assertFalse(pager.hasPrevious());
Assertions.assertNull(pager.getStartCursor());
Assertions.assertNull(pager.getEndCursor());
}
}
Loading
Loading