DATAGEODE-83 - Override generated OQL from Repository query methods.

This commit is contained in:
John Blum
2018-02-16 16:08:40 -08:00
parent 0e47900316
commit 0f7b66230a
35 changed files with 2735 additions and 876 deletions

View File

@@ -0,0 +1,142 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.repository.config;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.function.Supplier;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.repository.sample.Animal;
import org.springframework.data.gemfire.repository.sample.Plant;
import org.springframework.data.gemfire.repository.sample.PlantRepository;
import org.springframework.data.gemfire.repository.sample.RabbitRepository;
import org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMockObjects;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.repository.Repository;
/**
* Integration tests for Spring Data [GemFire] Repositories testing compatibility of {@link Region}
* {@link RegionAttributes#getKeyConstraint() key type}, {@link Repository} {@link Class ID type}
* and {@link PersistentEntity entity} {@link Class ID type}.
*
* @author John Blum
* @see org.junit.Test
* @see org.springframework.context.ConfigurableApplicationContext
* @since 1.4.0
* @link https://github.com/spring-projects/spring-data-gemfire/pull/55
*/
public class IncompatibleRegionKeyRepositoryIdAndEntityIdRepositoryIntegrationTests {
private static ConfigurableApplicationContext newApplicationContext(Class<?> testConfiguration) {
return new AnnotationConfigApplicationContext(testConfiguration);
}
private void withTestConfigurationExpectIllegalArgumentExceptionWithMessage(Class<?> testConfiguration,
Class<? extends Repository> repositoryType, Supplier<String> exceptionMessage) {
try {
ConfigurableApplicationContext applicationContext = newApplicationContext(testConfiguration);
assertThat(applicationContext.getBean(repositoryType)).isNotNull();
}
catch (BeanCreationException expected) {
assertThat(expected).hasCauseInstanceOf(IllegalArgumentException.class);
assertThat(expected.getCause()).hasMessage(exceptionMessage.get());
throw (IllegalArgumentException) expected.getCause();
}
}
@Test(expected = IllegalArgumentException.class)
public void withRegionUsingStringKeyAndRepositoryUsingLongId() {
withTestConfigurationExpectIllegalArgumentExceptionWithMessage(
TestIncompatibleRegionKeyRepositoryIdTypeConfiguration.class,
RabbitRepository.class,
() -> String.format("Region [/Rabbits] requires keys of type [%1$s], but Repository [%2$s] declared an id of type [%3$s]",
String.class.getName(), RabbitRepository.class.getName(), Long.class.getName()));
}
@Test(expected = IllegalArgumentException.class)
public void withRepositoryUsingStringIdAndEntityUsingLongId() {
withTestConfigurationExpectIllegalArgumentExceptionWithMessage(
TestIncompatibleRepositoryIdEntityIdTypeConfiguration.class,
PlantRepository.class,
() -> String.format("Repository [%1$s] declared an id of type [%2$s], but entity [%3$s] has an id of type [%4$s]",
PlantRepository.class.getName(), String.class.getName(), Plant.class.getName(), Long.class.getName()));
}
@ClientCacheApplication
@EnableGemFireMockObjects
@EnableGemfireRepositories(basePackageClasses = RabbitRepository.class,
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = RabbitRepository.class)
)
@SuppressWarnings("unused")
static class TestIncompatibleRegionKeyRepositoryIdTypeConfiguration {
@Bean("Rabbits")
public ClientRegionFactoryBean<String, Animal> clientRegion(GemFireCache gemfireCache) {
ClientRegionFactoryBean<String, Animal> clientRegion = new ClientRegionFactoryBean<>();
clientRegion.setCache(gemfireCache);
clientRegion.setClose(false);
clientRegion.setKeyConstraint(String.class);
clientRegion.setShortcut(ClientRegionShortcut.LOCAL);
clientRegion.setValueConstraint(Animal.class);
return clientRegion;
}
}
@ClientCacheApplication
@EnableGemFireMockObjects
@EnableGemfireRepositories(basePackageClasses = PlantRepository.class,
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = PlantRepository.class)
)
@SuppressWarnings("unused")
static class TestIncompatibleRepositoryIdEntityIdTypeConfiguration {
@Bean("Plants")
public ClientRegionFactoryBean<Object, Object> clientRegion(GemFireCache gemfireCache) {
ClientRegionFactoryBean<Object, Object> clientRegion = new ClientRegionFactoryBean<>();
clientRegion.setCache(gemfireCache);
clientRegion.setClose(false);
clientRegion.setShortcut(ClientRegionShortcut.PROXY);
return clientRegion;
}
}
}

View File

@@ -17,23 +17,18 @@
package org.springframework.data.gemfire.repository.query;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.data.repository.query.parser.PartTree;
/**
* Test suite of test cases testing the contract and functionality of the {@link QueryBuilder} class.
* Unit tests for {@link QueryBuilder} class.
*
* @author John Blum
* @see org.junit.Test
@@ -43,12 +38,11 @@ import org.springframework.data.repository.query.parser.PartTree;
*/
public class QueryBuilderUnitTests {
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void createQueryBuilderWithDistinctQuery() {
GemfirePersistentEntity<?> mockPersistentEntity = mock(GemfirePersistentEntity.class);
PartTree mockPartTree = mock(PartTree.class);
when(mockPersistentEntity.getRegionName()).thenReturn("Example");
@@ -64,7 +58,9 @@ public class QueryBuilderUnitTests {
@Test
public void createQueryBuilderWithNonDistinctQuery() {
GemfirePersistentEntity<?> mockPersistentEntity = mock(GemfirePersistentEntity.class);
PartTree mockPartTree = mock(PartTree.class);
when(mockPersistentEntity.getRegionName()).thenReturn("Example");
@@ -78,24 +74,31 @@ public class QueryBuilderUnitTests {
verify(mockPartTree, times(1)).isDistinct();
}
@Test
@Test(expected = IllegalArgumentException.class)
public void createQueryBuilderWithNullQueryString() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(is(equalTo("An OQL Query must be specified")));
new QueryBuilder(null);
try {
new QueryBuilder(null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Query is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
@SuppressWarnings("all")
public void createWithPredicate() {
Predicate mockPredicate = mock(Predicate.class);
when(mockPredicate.toString(eq(QueryBuilder.DEFAULT_ALIAS))).thenReturn("x.id = 1");
QueryBuilder queryBuilder = new QueryBuilder(
String.format("SELECT * FROM /Example %s", QueryBuilder.DEFAULT_ALIAS));
QueryBuilder queryBuilder =
new QueryBuilder(String.format("SELECT * FROM /Example %s", QueryBuilder.DEFAULT_ALIAS));
QueryString queryString = queryBuilder.create(mockPredicate);
@@ -107,6 +110,7 @@ public class QueryBuilderUnitTests {
@Test
public void createWithNullPredicate() {
QueryBuilder queryBuilder = new QueryBuilder("SELECT * FROM /Example");
QueryString queryString = queryBuilder.create(null);

View File

@@ -0,0 +1,227 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.repository.query;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.gemfire.repository.sample.PersonRepository;
import org.springframework.data.gemfire.repository.sample.User;
import org.springframework.data.gemfire.repository.sample.UserRepository;
import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* The QueryPostProcessorIntegrationTests class...
*
* @author John Blum
* @since 1.0.0
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
public class QueryPostProcessorIntegrationTests {
private static final AtomicLong idSequence = new AtomicLong(0L);
@Autowired
private FindOrderedLimitedPeopleByFirstNameQueryPostProcessor peopleQueryPostProcessor;
@Autowired
private PersonRepository personRepository;
@Autowired
private RecordingQueryPostProcessor recordingQueryPostProcessor;
@Autowired
private UserRepository userRepository;
private static Person newPerson(String firstName, String lastName) {
Person person = new Person(firstName, lastName);
person.id = idSequence.incrementAndGet();
return person;
}
@Before
public void setup() {
this.personRepository.save(newPerson("Jon", "Doe"));
this.personRepository.save(newPerson("Cookie", "Doe"));
this.personRepository.save(newPerson("Pie", "Doe"));
this.personRepository.save(newPerson("Sour", "Doe"));
this.personRepository.save(newPerson("Jack", "BeNimble"));
this.personRepository.save(newPerson("Jack", "BeQuick"));
this.personRepository.save(newPerson("Jack", "Black"));
this.personRepository.save(newPerson("Jack", "JumpedOverTheCandleStick"));
this.personRepository.save(newPerson("Jack", "Handy"));
this.personRepository.save(newPerson("Jack", "Sparrow"));
this.personRepository.save(newPerson("Agent", "Smith"));
this.userRepository.save(new User("abuser"));
this.userRepository.save(new User("jdoe"));
this.userRepository.save(new User("root"));
}
@Test
public void queryPostProcessingProcessesGeneratedOqlQueries() {
assertThat(this.personRepository.count()).isEqualTo(11);
assertThat(this.userRepository.count()).isEqualTo(3);
assertThat(this.recordingQueryPostProcessor.queries).isEmpty();
List<User> users = this.userRepository.findDistinctByUsernameLike("%doe");
assertThat(users).hasSize(1);
assertThat(this.recordingQueryPostProcessor.queries).hasSize(1);
assertThat(this.recordingQueryPostProcessor.queries)
.containsExactly("SELECT DISTINCT * FROM /Users x WHERE x.username LIKE $1");
Collection<Person> bakingDoes = this.personRepository.findByFirstnameIn("Cookie", "Pie", "Sour");
assertThat(bakingDoes).hasSize(3);
assertThat(this.recordingQueryPostProcessor.queries).hasSize(2);
assertThat(this.recordingQueryPostProcessor.queries).containsExactly(
"SELECT DISTINCT * FROM /Users x WHERE x.username LIKE $1",
"SELECT * FROM /simple x WHERE x.firstname IN SET ('Cookie', 'Pie', 'Sour')"
);
Collection<Person> jacks = this.personRepository.findByFirstname("Jack");
assertThat(jacks).hasSize(1);
assertThat(jacks.stream().findFirst().map(Person::getName).orElse(null)).isEqualTo("Jack Sparrow");
assertThat(this.recordingQueryPostProcessor.queries).hasSize(3);
assertThat(this.recordingQueryPostProcessor.queries).containsExactly(
"SELECT DISTINCT * FROM /Users x WHERE x.username LIKE $1",
"SELECT * FROM /simple x WHERE x.firstname IN SET ('Cookie', 'Pie', 'Sour')",
"SELECT DISTINCT * FROM /simple x WHERE x.firstname = $1 ORDER BY lastname DESC LIMIT 1"
);
}
@ClientCacheApplication
@SuppressWarnings("unused")
static class TestConfiguration {
@Bean("simple")
public ClientRegionFactoryBean<Object, Object> peopleRegion(GemFireCache gemfireCache) {
ClientRegionFactoryBean<Object, Object> clientRegion = new ClientRegionFactoryBean<>();
clientRegion.setCache(gemfireCache);
clientRegion.setClose(false);
clientRegion.setShortcut(ClientRegionShortcut.LOCAL);
return clientRegion;
}
@Bean("Users")
public ClientRegionFactoryBean<Object, Object> usersRegion(GemFireCache gemfireCache) {
ClientRegionFactoryBean<Object, Object> clientRegion = new ClientRegionFactoryBean<>();
clientRegion.setCache(gemfireCache);
clientRegion.setClose(false);
clientRegion.setShortcut(ClientRegionShortcut.LOCAL);
return clientRegion;
}
@Bean
GemfireMappingContext mappingContext() {
return new GemfireMappingContext();
}
@Bean
GemfireRepositoryFactoryBean<PersonRepository, Person, Long> personRepository() {
return new GemfireRepositoryFactoryBean<>(PersonRepository.class);
}
@Bean
GemfireRepositoryFactoryBean<UserRepository, User, String> userRepository() {
return new GemfireRepositoryFactoryBean<>(UserRepository.class);
}
@Bean
FindOrderedLimitedPeopleByFirstNameQueryPostProcessor personQueryPostProcess() {
return new FindOrderedLimitedPeopleByFirstNameQueryPostProcessor(1);
}
@Bean
RecordingQueryPostProcessor recordingQueryPostProcessor() {
return new RecordingQueryPostProcessor();
}
}
static class FindOrderedLimitedPeopleByFirstNameQueryPostProcessor implements QueryPostProcessor<PersonRepository, String> {
private final int limit;
FindOrderedLimitedPeopleByFirstNameQueryPostProcessor(int limit) {
this.limit = limit;
}
@Override
public int getOrder() {
return 0;
}
@Override
public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {
return "findByFirstname".equals(queryMethod.getName())
? query.trim().replace("SELECT", "SELECT DISTINCT")
.concat(" ORDER BY lastname DESC").concat(String.format(" LIMIT %d", this.limit))
: query;
}
}
static class RecordingQueryPostProcessor implements QueryPostProcessor<Repository, String> {
List<String> queries = new CopyOnWriteArrayList<>();
@Override
public int getOrder() {
return 1;
}
@Override
public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {
this.queries.add(query);
return query;
}
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.repository.query;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.mockito.InOrder;
import org.springframework.data.repository.query.QueryMethod;
/**
* Unit tests for {@link QueryPostProcessor}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.springframework.data.gemfire.repository.query.QueryPostProcessor
* @since 1.0.0
*/
public class QueryPostProcessorUnitTests {
@Test
@SuppressWarnings("unchecked")
public void processAfterReturnsCompositeQueryPostProcessorAndPostProcessesInOrder() {
QueryMethod mockQueryMethod = mock(QueryMethod.class);
String query = "SELECT * FROM /Test";
QueryPostProcessor<?, String> mockQueryPostProcessorOne = mock(QueryPostProcessor.class);
QueryPostProcessor<?, String> mockQueryPostProcessorTwo = mock(QueryPostProcessor.class);
when(mockQueryPostProcessorOne.processAfter(any())).thenCallRealMethod();
when(mockQueryPostProcessorOne.postProcess(any(QueryMethod.class), anyString(), any())).thenReturn(query);
when(mockQueryPostProcessorTwo.postProcess(any(QueryMethod.class), anyString(), any())).thenReturn(query);
QueryPostProcessor<?, String> composite = mockQueryPostProcessorOne.processAfter(mockQueryPostProcessorTwo);
assertThat(composite).isNotNull();
assertThat(composite).isNotSameAs(mockQueryPostProcessorOne);
assertThat(composite).isNotSameAs(mockQueryPostProcessorTwo);
assertThat(composite.postProcess(mockQueryMethod, query)).isEqualTo(query);
InOrder inOrder = inOrder(mockQueryPostProcessorOne, mockQueryPostProcessorTwo);
inOrder.verify(mockQueryPostProcessorTwo, times(1))
.postProcess(eq(mockQueryMethod), eq(query), any());
inOrder.verify(mockQueryPostProcessorOne, times(1))
.postProcess(eq(mockQueryMethod), eq(query), any());
}
@Test
public void processAfterReturnsThis() {
QueryPostProcessor<?, ?> mockQueryPostProcessor = mock(QueryPostProcessor.class);
when(mockQueryPostProcessor.processAfter(any())).thenCallRealMethod();
assertThat(mockQueryPostProcessor.processAfter(null)).isSameAs(mockQueryPostProcessor);
}
@Test
@SuppressWarnings("unchecked")
public void processBeforeReturnsCompositeQueryPostProcessorAndPostProcessesInOrder() {
QueryMethod mockQueryMethod = mock(QueryMethod.class);
String query = "SELECT * FROM /Test";
QueryPostProcessor<?, String> mockQueryPostProcessorOne = mock(QueryPostProcessor.class);
QueryPostProcessor<?, String> mockQueryPostProcessorTwo = mock(QueryPostProcessor.class);
when(mockQueryPostProcessorOne.processBefore(any())).thenCallRealMethod();
when(mockQueryPostProcessorOne.postProcess(any(QueryMethod.class), anyString(), any())).thenReturn(query);
when(mockQueryPostProcessorTwo.postProcess(any(QueryMethod.class), anyString(), any())).thenReturn(query);
QueryPostProcessor<?, String> composite = mockQueryPostProcessorOne.processBefore(mockQueryPostProcessorTwo);
assertThat(composite).isNotNull();
assertThat(composite).isNotSameAs(mockQueryPostProcessorOne);
assertThat(composite).isNotSameAs(mockQueryPostProcessorTwo);
assertThat(composite.postProcess(mockQueryMethod, query)).isEqualTo(query);
InOrder inOrder = inOrder(mockQueryPostProcessorOne, mockQueryPostProcessorTwo);
inOrder.verify(mockQueryPostProcessorOne, times(1))
.postProcess(eq(mockQueryMethod), eq(query), any());
inOrder.verify(mockQueryPostProcessorTwo, times(1))
.postProcess(eq(mockQueryMethod), eq(query), any());
}
@Test
public void processBeforeReturnsThis() {
QueryPostProcessor<?, ?> mockQueryPostProcessor = mock(QueryPostProcessor.class);
when(mockQueryPostProcessor.processBefore(any())).thenCallRealMethod();
assertThat(mockQueryPostProcessor.processBefore(null)).isSameAs(mockQueryPostProcessor);
}
}

View File

@@ -17,9 +17,6 @@
package org.springframework.data.gemfire.repository.query;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -61,61 +58,110 @@ public class QueryStringUnitTests {
@SuppressWarnings("rawtypes")
Region region;
protected Sort.Order newSortOrder(String property) {
private Sort.Order newSortOrder(String property) {
return newSortOrder(property, Sort.Direction.ASC);
}
protected Sort.Order newSortOrder(String property, Sort.Direction direction) {
private Sort.Order newSortOrder(String property, Sort.Direction direction) {
return new Sort.Order(direction, property);
}
protected Sort newSort(Sort.Order... orders) {
return new Sort(orders);
private Sort newSort(Sort.Order... orders) {
return Sort.by(orders);
}
@Test
public void createQueryStringWithDomainType() {
public void constructQueryStringWithDomainType() {
assertThat(new QueryString(Person.class).toString()).isEqualTo("SELECT * FROM /Person");
}
@Test
public void createQueryStringWithDomainTypeHavingCount() {
public void constructQueryStringWithDomainTypeAsCount() {
assertThat(new QueryString(Person.class, true).toString()).isEqualTo("SELECT count(*) FROM /Person");
}
@Test
public void createQueryStringWithNullDomainType() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(is(equalTo("domainType must not be null")));
@Test(expected = IllegalArgumentException.class)
public void constructQueryStringWithNullDomainType() {
new QueryString((Class<?>) null);
try {
new QueryString((Class<?>) null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Domain type is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void createQueryStringWithQuery() {
public void constructQueryStringWithQuery() {
String query = "SELECT * FROM /Example";
assertThat(new QueryString(query).toString()).isEqualTo(query);
}
@Test
public void createQueryStringWithUnspecifiedQueryThrowsIllegalArgumentException() {
assertUnspecifiedQueryThrowsIllegalArgumentException("");
@Test(expected = IllegalArgumentException.class)
public void constructQueryStringWithBlankQueryThrowsIllegalArgumentException() {
assertUnspecifiedQueryThrowsIllegalArgumentException(" ");
}
@Test(expected = IllegalArgumentException.class)
public void constructQueryStringWithEmptyQueryThrowsIllegalArgumentException() {
assertUnspecifiedQueryThrowsIllegalArgumentException("");
}
@Test(expected = IllegalArgumentException.class)
public void constructQueryStringWithNullQueryThrowsIllegalArgumentException() {
assertUnspecifiedQueryThrowsIllegalArgumentException(null);
}
protected void assertUnspecifiedQueryThrowsIllegalArgumentException(String query) {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(is(equalTo("An OQL Query must be specified")));
private void assertUnspecifiedQueryThrowsIllegalArgumentException(String query) {
new QueryString(query);
try {
new QueryString(query);
}
catch (Exception expected) {
assertThat(expected).hasMessage("Query [%s] is required", query);
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void queryStringOfQuery() {
QueryString query = QueryString.of("SELECT * FROM /Test");
assertThat(query).isNotNull();
assertThat(query.toString()).isEqualTo("SELECT * FROM /Test");
}
@Test
public void queryStringFromDomainType() {
QueryString query = QueryString.from(Person.class);
assertThat(query).isNotNull();
assertThat(query.toString()).isEqualTo("SELECT * FROM /Person");
}
@Test
public void queryStringCountingObjectsOfDomainType() {
QueryString query = QueryString.count(Person.class);
assertThat(query).isNotNull();
assertThat(query.toString()).isEqualTo("SELECT count(*) FROM /Person");
}
@Test
public void hintPatternMatches() {
assertThat(matches(HINT_PATTERN, "<HINT 'ExampleIndex'>")).isTrue();
assertThat(matches(HINT_PATTERN, "<HINT 'IdIdx'> SELECT * FROM /Example WHERE id = $1")).isTrue();
assertThat(matches(HINT_PATTERN, "<HINT 'LastNameIdx', 'BirthDateIdx'> SELECT * FROM /Person WHERE lastName = $1 AND birthDate = $2")).isTrue();
@@ -123,6 +169,7 @@ public class QueryStringUnitTests {
@Test
public void hintPatternNoMatches() {
assertThat(matches(HINT_PATTERN, "HINT")).isFalse();
assertThat(matches(HINT_PATTERN, "<HINT>")).isFalse();
assertThat(matches(HINT_PATTERN, "<HINT ''>")).isFalse();
@@ -136,6 +183,7 @@ public class QueryStringUnitTests {
@Test
public void importPatternMatches() {
assertThat(matches(IMPORT_PATTERN, "IMPORT *;")).isTrue();
assertThat(matches(IMPORT_PATTERN, "IMPORT org.example.*;")).isTrue();
assertThat(matches(IMPORT_PATTERN, "IMPORT org.example.Type;")).isTrue();
@@ -144,6 +192,7 @@ public class QueryStringUnitTests {
@Test
public void importPatternNoMatches() {
assertThat(matches(IMPORT_PATTERN, "IMPORT")).isFalse();
assertThat(matches(IMPORT_PATTERN, "IMPORT ;")).isFalse();
assertThat(matches(IMPORT_PATTERN, "IMPORT *")).isFalse();
@@ -153,6 +202,7 @@ public class QueryStringUnitTests {
@Test
public void limitPatternMatches() {
assertThat(matches(LIMIT_PATTERN, "LIMIT 0")).isTrue();
assertThat(matches(LIMIT_PATTERN, "LIMIT 1")).isTrue();
assertThat(matches(LIMIT_PATTERN, "LIMIT 10")).isTrue();
@@ -162,6 +212,7 @@ public class QueryStringUnitTests {
@Test
public void limitPatternNoMatches() {
assertThat(matches(LIMIT_PATTERN, "LIMIT")).isFalse();
assertThat(matches(LIMIT_PATTERN, "LIMIT lO")).isFalse();
assertThat(matches(LIMIT_PATTERN, "LIMIT AF")).isFalse();
@@ -172,6 +223,7 @@ public class QueryStringUnitTests {
@Test
public void tracePatternMatches() {
assertThat(matches(TRACE_PATTERN, "<TRACE>")).isTrue();
assertThat(matches(TRACE_PATTERN, "<TRACE> SELECT * FROM /Example")).isTrue();
assertThat(matches(TRACE_PATTERN, "<TRACE>SELECT * FROM /Example")).isTrue();
@@ -180,56 +232,78 @@ public class QueryStringUnitTests {
@Test
public void tracePatternNoMatches() {
assertThat(matches(TRACE_PATTERN, "TRACE")).isFalse();
assertThat(matches(TRACE_PATTERN, "TRACE SELECT * FROM /Example")).isFalse();
assertThat(matches(TRACE_PATTERN, "<TRACE SELECT * FROM /Example>")).isFalse();
}
protected boolean matches(Pattern pattern, String value) {
private boolean matches(Pattern pattern, String value) {
return pattern.matcher(value).find();
}
@Test
public void asDistinctQuery() {
QueryString query = QueryString.of("SELECT * FROM /Test");
assertThat(query.asDistinct().toString()).isEqualTo("SELECT DISTINCT * FROM /Test");
}
@Test
public void asDistinctWithDistinctQuery() {
QueryString query = QueryString.of("SELECT DISTINCT * FROM /Test");
assertThat(query.asDistinct().toString()).isEqualTo("SELECT DISTINCT * FROM /Test");
}
// SGF-251
@Test
public void replacesDomainTypeSimpleNameWithRegionPathCorrectly() {
QueryString query = new QueryString(Person.class);
when(region.getFullPath()).thenReturn("/foo/bar");
QueryString query = QueryString.from(Person.class);
assertThat(query.forRegion(Person.class, region).toString()).isEqualTo("SELECT * FROM /foo/bar");
when(this.region.getFullPath()).thenReturn("/foo/bar");
verify(region, times(1)).getFullPath();
assertThat(query.toString()).isEqualTo("SELECT * FROM /Person");
assertThat(query.fromRegion(Person.class, this.region).toString()).isEqualTo("SELECT * FROM /foo/bar");
verify(this.region, times(1)).getFullPath();
}
// SGF-156, SGF-251
@Test
public void replacesFromClauseWithRegionPathCorrectly() {
QueryString query = new QueryString("SELECT * FROM /Persons p WHERE p.lastname = $1");
when(region.getFullPath()).thenReturn("/People");
QueryString query = QueryString.of("SELECT * FROM /Persons p WHERE p.lastname = $1");
assertThat(query.forRegion(Person.class, region).toString())
when(this.region.getFullPath()).thenReturn("/People");
assertThat(query.fromRegion(Person.class, this.region).toString())
.isEqualTo("SELECT * FROM /People p WHERE p.lastname = $1");
verify(region, times(1)).getFullPath();
verify(this.region, times(1)).getFullPath();
}
// SGF-252
@Test
public void replacesFullyQualifiedSubRegionPathWithRegionPathCorrectly() {
QueryString query = new QueryString("SELECT * FROM //Local/Root/Users u WHERE u.username = $1");
when(region.getFullPath()).thenReturn("/Remote/Root/Users");
QueryString query = QueryString.of("SELECT * FROM //Local/Root/Users u WHERE u.username = $1");
assertThat(query.forRegion(RootUser.class, region).toString())
when(this.region.getFullPath()).thenReturn("/Remote/Root/Users");
assertThat(query.fromRegion(RootUser.class, this.region).toString())
.isEqualTo("SELECT * FROM /Remote/Root/Users u WHERE u.username = $1");
verify(region, times(1)).getFullPath();
verify(this.region, times(1)).getFullPath();
}
@Test
public void bindsInValuesCorrectly() {
QueryString query = new QueryString("SELECT * FROM /Collection WHERE elements IN SET $1");
QueryString query = QueryString.of("SELECT * FROM /Collection WHERE elements IN SET $1");
assertThat(query.bindIn(Arrays.asList(1, 2, 3)).toString())
.isEqualTo("SELECT * FROM /Collection WHERE elements IN SET ('1', '2', '3')");
@@ -237,22 +311,26 @@ public class QueryStringUnitTests {
@Test
public void detectsInParameterIndexesCorrectly() {
QueryString query = new QueryString("SELECT * FROM /Example WHERE values IN SET $1 OR IN SET $2");
QueryString query = QueryString.of("SELECT * FROM /Example WHERE values IN SET $1 OR IN SET $2");
assertThat(query.getInParameterIndexes()).isEqualTo(Arrays.asList(1, 2));
}
@Test
public void addsNoOrderByClauseCorrectly() {
QueryString query = new QueryString("SELECT * FROM /People p").orderBy(null);
QueryString query = QueryString.of("SELECT * FROM /People p").orderBy(null);
assertThat(query.toString()).isEqualTo("SELECT * FROM /People p");
}
@Test
public void addsOrderByClauseCorrectly() {
QueryString query = new QueryString("SELECT * FROM /People p WHERE p.lastName = $1")
.orderBy(newSort(newSortOrder("lastName", Sort.Direction.DESC), newSortOrder("firstName")));
QueryString query = QueryString.of("SELECT * FROM /People p WHERE p.lastName = $1")
.orderBy(newSort(newSortOrder("lastName", Sort.Direction.DESC),
newSortOrder("firstName")));
assertThat(query.toString())
.isEqualTo("SELECT DISTINCT * FROM /People p WHERE p.lastName = $1 ORDER BY lastName DESC, firstName ASC");
@@ -260,7 +338,8 @@ public class QueryStringUnitTests {
@Test
public void addsSingleOrderByClauseCorrectly() {
QueryString query = new QueryString("SELECT DISTINCT p.lastName FROM /People p WHERE p.firstName = $1")
QueryString query = QueryString.of("SELECT DISTINCT p.lastName FROM /People p WHERE p.firstName = $1")
.orderBy(newSort(newSortOrder("lastName")));
assertThat(query.toString())
@@ -269,16 +348,18 @@ public class QueryStringUnitTests {
@Test
public void withHints() {
assertThat(new QueryString("SELECT * FROM /Example").withHints("IdIdx").toString())
assertThat(QueryString.of("SELECT * FROM /Example").withHints("IdIdx").toString())
.isEqualTo("<HINT 'IdIdx'> SELECT * FROM /Example");
assertThat(new QueryString("SELECT * FROM /Example").withHints("IdIdx", "SpatialIdx", "TxDateIdx").toString())
assertThat(QueryString.of("SELECT * FROM /Example").withHints("IdIdx", "SpatialIdx", "TxDateIdx").toString())
.isEqualTo("<HINT 'IdIdx', 'SpatialIdx', 'TxDateIdx'> SELECT * FROM /Example");
}
@Test
public void withoutHints() {
QueryString expectedQueryString = new QueryString("SELECT * FROM /Example");
QueryString expectedQueryString = QueryString.of("SELECT * FROM /Example");
assertThat(expectedQueryString.withHints()).isSameAs(expectedQueryString);
assertThat(expectedQueryString.withHints((String[]) null)).isSameAs(expectedQueryString);
@@ -286,13 +367,14 @@ public class QueryStringUnitTests {
@Test
public void withImport() {
assertThat(new QueryString("SELECT * FROM /People").withImport("org.example.app.domain.Person").toString())
assertThat(QueryString.of("SELECT * FROM /People").withImport("org.example.app.domain.Person").toString())
.isEqualTo("IMPORT org.example.app.domain.Person; SELECT * FROM /People");
}
@Test
public void withoutImport() {
QueryString expectedQueryString = new QueryString("SELECT * FROM /Example");
QueryString expectedQueryString = QueryString.of("SELECT * FROM /Example");
assertThat(expectedQueryString.withImport(null)).isSameAs(expectedQueryString);
assertThat(expectedQueryString.withImport("")).isSameAs(expectedQueryString);
@@ -301,40 +383,47 @@ public class QueryStringUnitTests {
@Test
public void withLimit() {
assertThat(new QueryString("SELECT * FROM /Example").withLimit(10).toString())
assertThat(QueryString.of("SELECT * FROM /Example").withLimit(10).toString())
.isEqualTo("SELECT * FROM /Example LIMIT 10");
assertThat(new QueryString("SELECT * FROM /Example").withLimit(0).toString())
assertThat(QueryString.of("SELECT * FROM /Example").withLimit(0).toString())
.isEqualTo("SELECT * FROM /Example LIMIT 0");
assertThat(new QueryString("SELECT * FROM /Example").withLimit(-5).toString())
assertThat(QueryString.of("SELECT * FROM /Example").withLimit(-5).toString())
.isEqualTo("SELECT * FROM /Example LIMIT -5");
}
@Test
public void withoutLimit() {
QueryString expectedQueryString = new QueryString("SELECT * FROM /Example");
QueryString expectedQueryString = QueryString.of("SELECT * FROM /Example");
assertThat(expectedQueryString.withLimit(null)).isSameAs(expectedQueryString);
}
@Test
public void withTrace() {
assertThat(new QueryString("SELECT * FROM /Example").withTrace().toString())
assertThat(QueryString.of("SELECT * FROM /Example").withTrace().toString())
.isEqualTo("<TRACE> SELECT * FROM /Example");
}
@Test
public void withHintAndTrace() {
assertThat(new QueryString("SELECT * FROM /Example").withHints("IdIdx").withTrace().toString())
assertThat(QueryString.of("SELECT * FROM /Example").withHints("IdIdx").withTrace().toString())
.isEqualTo("<TRACE> <HINT 'IdIdx'> SELECT * FROM /Example");
}
@Test
public void withHintImportLimitAndTrace() {
QueryString query = new QueryString("SELECT * FROM /Example");
assertThat(query.withImport("org.example.domain.Type").withHints("IdIdx", "NameIdx").withLimit(20).withTrace().toString())
QueryString query = QueryString.of("SELECT * FROM /Example")
.withImport("org.example.domain.Type")
.withHints("IdIdx", "NameIdx")
.withLimit(20)
.withTrace();
assertThat(query.toString())
.isEqualTo("<TRACE> <HINT 'IdIdx', 'NameIdx'> IMPORT org.example.domain.Type; SELECT * FROM /Example LIMIT 20");
}
}

View File

@@ -18,9 +18,7 @@ package org.springframework.data.gemfire.repository.query;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -59,7 +57,9 @@ public class StringBasedGemfireRepositoryQueryTest {
@Test
public void testToCollectionWithSelectResults() {
SelectResults mockSelectResults = mock(SelectResults.class, "testToCollectionWithSelectResults.SelectResults");
List<String> expectedList = Arrays.asList("one", "two", "three");
when(mockSelectResults.asList()).thenReturn(expectedList);
@@ -71,7 +71,9 @@ public class StringBasedGemfireRepositoryQueryTest {
@Test
public void testToCollectionWithResultsBag() {
ResultsBag mockResultsBag = mock(ResultsBag.class, "testToCollectionWithResultsBag.ResultsBag");
List<String> expectedList = Arrays.asList("a", "b", "c");
when(mockResultsBag.asList()).thenReturn(expectedList);
@@ -83,7 +85,9 @@ public class StringBasedGemfireRepositoryQueryTest {
@Test
public void testToCollectionWithCollection() {
List<String> expectedList = Arrays.asList("x", "y", "z");
Collection<?> actualList = repositoryQuery.toCollection(expectedList);
assertSame(expectedList, actualList);
@@ -91,7 +95,9 @@ public class StringBasedGemfireRepositoryQueryTest {
@Test
public void testToCollectionWithArray() {
Object[] array = { 1, 2, 3 };
Collection<?> list = repositoryQuery.toCollection(array);
assertNotNull(list);
@@ -103,6 +109,7 @@ public class StringBasedGemfireRepositoryQueryTest {
@Test
public void testToCollectionWithSingleObject() {
Collection<?> list = repositoryQuery.toCollection("test");
assertTrue(list instanceof List);
@@ -113,6 +120,7 @@ public class StringBasedGemfireRepositoryQueryTest {
@Test
public void testToCollectionWithNull() {
Collection<?> list = repositoryQuery.toCollection(null);
assertNotNull(list);
@@ -121,6 +129,7 @@ public class StringBasedGemfireRepositoryQueryTest {
@Test
public void applyAllQueryAnnotationExtensions() {
GemfireQueryMethod mockQueryMethod = mock(GemfireQueryMethod.class, "MockGemfireQueryMethod");
when(mockQueryMethod.hasHint()).thenReturn(true);
@@ -131,18 +140,18 @@ public class StringBasedGemfireRepositoryQueryTest {
when(mockQueryMethod.getLimit()).thenReturn(10);
when(mockQueryMethod.hasTrace()).thenReturn(true);
QueryString queryString = new QueryString("SELECT * FROM /Example");
QueryString queryString = QueryString.of("SELECT * FROM /Example");
assertThat(queryString.toString(), is(equalTo("SELECT * FROM /Example")));
StringBasedGemfireRepositoryQuery repositoryQuery = new StringBasedGemfireRepositoryQuery();
QueryString actualQueryString = repositoryQuery.applyQueryAnnotationExtensions(mockQueryMethod, queryString);
String postProcessedQueryString = repositoryQuery.getQueryPostProcessor()
.postProcess(mockQueryMethod, queryString.toString());
assertThat(actualQueryString, is(notNullValue()));
assertThat(actualQueryString, is(not(sameInstance(queryString))));
assertThat(actualQueryString.toString(), is(equalTo(
"<TRACE> <HINT 'IdIdx', 'NameIdx'> IMPORT org.example.domain.Type; SELECT * FROM /Example LIMIT 10")));
assertThat(postProcessedQueryString, is(notNullValue()));
assertThat(postProcessedQueryString,
is(equalTo("<TRACE> <HINT 'IdIdx', 'NameIdx'> IMPORT org.example.domain.Type; SELECT * FROM /Example LIMIT 10")));
verify(mockQueryMethod, times(1)).hasHint();
verify(mockQueryMethod, times(1)).getHints();
@@ -155,6 +164,7 @@ public class StringBasedGemfireRepositoryQueryTest {
@Test
public void applyHintLimitAndTraceQueryAnnotationExtensionsWithExistingHintAndLimit() {
GemfireQueryMethod mockQueryMethod = mock(GemfireQueryMethod.class, "MockGemfireQueryMethod");
when(mockQueryMethod.hasHint()).thenReturn(true);
@@ -170,12 +180,11 @@ public class StringBasedGemfireRepositoryQueryTest {
StringBasedGemfireRepositoryQuery repositoryQuery = new StringBasedGemfireRepositoryQuery();
QueryString actualQueryString = repositoryQuery.applyQueryAnnotationExtensions(mockQueryMethod, queryString);
String postProcessedQueryString = repositoryQuery.getQueryPostProcessor().postProcess(mockQueryMethod, queryString.toString());
assertThat(actualQueryString, is(notNullValue()));
assertThat(actualQueryString, is(not(sameInstance(queryString))));
assertThat(actualQueryString.toString(), is(equalTo(
"<TRACE> <HINT 'LastNameIdx'> SELECT * FROM /Example LIMIT 25")));
assertThat(postProcessedQueryString, is(notNullValue()));
assertThat(postProcessedQueryString,
is(equalTo("<TRACE> <HINT 'LastNameIdx'> SELECT * FROM /Example LIMIT 25")));
verify(mockQueryMethod, times(1)).hasHint();
verify(mockQueryMethod, never()).getHints();
@@ -188,6 +197,7 @@ public class StringBasedGemfireRepositoryQueryTest {
@Test
public void applyImportAndTraceQueryAnnotationExtensionsWithExistingTrace() {
GemfireQueryMethod mockQueryMethod = mock(GemfireQueryMethod.class, "MockGemfireQueryMethod");
when(mockQueryMethod.hasHint()).thenReturn(false);
@@ -202,12 +212,11 @@ public class StringBasedGemfireRepositoryQueryTest {
StringBasedGemfireRepositoryQuery repositoryQuery = new StringBasedGemfireRepositoryQuery();
QueryString actualQueryString = repositoryQuery.applyQueryAnnotationExtensions(mockQueryMethod, queryString);
String postProcessedQueryString = repositoryQuery.getQueryPostProcessor().postProcess(mockQueryMethod, queryString.toString());
assertThat(actualQueryString, is(notNullValue()));
assertThat(actualQueryString, is(not(sameInstance(queryString))));
assertThat(actualQueryString.toString(), is(equalTo(
"IMPORT org.example.domain.Type; <TRACE> SELECT * FROM /Example")));
assertThat(postProcessedQueryString, is(notNullValue()));
assertThat(postProcessedQueryString,
is(equalTo("IMPORT org.example.domain.Type; <TRACE> SELECT * FROM /Example")));
verify(mockQueryMethod, times(1)).hasHint();
verify(mockQueryMethod, never()).getHints();
@@ -217,5 +226,4 @@ public class StringBasedGemfireRepositoryQueryTest {
verify(mockQueryMethod, never()).getLimit();
verify(mockQueryMethod, times(1)).hasTrace();
}
}

View File

@@ -21,6 +21,8 @@ import org.springframework.data.gemfire.mapping.annotation.Region;
import org.springframework.data.gemfire.mapping.annotation.ReplicateRegion;
import org.springframework.util.ObjectUtils;
import lombok.Data;
/**
* The Customer class is a class abstraction modeling a Customer.
*
@@ -29,6 +31,7 @@ import org.springframework.util.ObjectUtils;
* @see Region
* @since 1.0.0
*/
@Data
@ReplicateRegion("Customers")
@SuppressWarnings("unused")
public class Customer {
@@ -42,39 +45,15 @@ public class Customer {
public Customer() {
}
public Customer(final Long id) {
public Customer(Long id) {
this.id = id;
}
public Customer(final String firstName, final String lastName) {
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(final String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(final String lastName) {
this.lastName = lastName;
}
public String getName() {
return String.format("%1$s %2$s", getFirstName(), getLastName());
}
@@ -85,7 +64,8 @@ public class Customer {
@Override
public boolean equals(final Object obj) {
if (obj == this) {
if (this == obj) {
return true;
}
@@ -100,7 +80,7 @@ public class Customer {
&& ObjectUtils.nullSafeEquals(this.getLastName(), that.getLastName());
}
protected static int hashCodeIgnoreNull(final Object obj) {
protected static int hashCodeIgnoreNull(Object obj) {
return (obj != null ? obj.hashCode() : 0);
}
@@ -115,7 +95,6 @@ public class Customer {
@Override
public String toString() {
return String.format("%1$s %2$s", getFirstName(), getLastName());
return getName();
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright 2010-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.repository.sample;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* The IncompatibleRegionKeyEntityIdAnimalRepositoryTest class is a test suite of test cases testing the functionality
* behind PR #55 involving persisting application domain object/entities to multiple Regions in GemFire's Cache.
*
* @author John Blum
* @see org.junit.Test
* @see org.springframework.context.ConfigurableApplicationContext
* @since 1.4.0
* @link https://github.com/spring-projects/spring-data-gemfire/pull/55
*/
public class IncompatibleRegionKeyEntityIdAnimalRepositoryTest {
private static final String APPLICATION_CONTEXT_CONFIG_LOCATION = String.format("%1$s%2$s%1$s%3$s",
File.separator, AnimalRepositoryTest.class.getPackage().getName().replace('.', File.separatorChar),
String.format("%s-context.xml", IncompatibleRegionKeyEntityIdAnimalRepositoryTest.class.getSimpleName()));
@Test(expected = IllegalArgumentException.class)
public void storeAnimalHavingLongIdInRabbitsRegionWithStringKey() {
try {
ConfigurableApplicationContext applicationContext =
new ClassPathXmlApplicationContext(APPLICATION_CONTEXT_CONFIG_LOCATION);
applicationContext.getBean(RabbitRepository.class);
}
// NOTE the ClassCastException thrown from GemFire is unexpected; this is not correct and the identifying type
// mismatch should be caught and handled by GemfireRepositoryFactory.getTemplate(..) method on line 129
// (appropriately throwing an IllegalArgumentException) after satisfying the condition on line 128,
// which always occurs with the @Region annotation set on the domain class/entity!
catch (ClassCastException unexpected) {
//unexpected.printStackTrace(System.err);
//assertTrue(unexpected.getMessage().contains("key ( java.lang.Long ) does not satisfy keyConstraint ( java.lang.String )"));
fail(unexpected.getMessage());
}
catch (BeanCreationException expected) {
//expected.printStackTrace(System.err);
assertTrue(expected.getCause() instanceof IllegalArgumentException);
assertEquals(String.format("The Region referenced only supports keys of type [%1$s], but the entity to be stored has an id of type [%2$s]",
String.class.getName(), Long.class.getName()), expected.getCause().getMessage());
throw (IllegalArgumentException) expected.getCause();
}
}
}

View File

@@ -33,20 +33,20 @@ import org.springframework.util.ObjectUtils;
public class Plant {
@Id
private String id;
private Long id;
private String name;
public String getId() {
return id;
public Long getId() {
return this.id;
}
public void setId(String id) {
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
return this.name;
}
public void setName(String name) {
@@ -55,7 +55,8 @@ public class Plant {
@Override
public boolean equals(final Object obj) {
if (obj == this) {
if (this == obj) {
return true;
}
@@ -71,9 +72,12 @@ public class Plant {
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getId());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getName());
return hashValue;
}
@@ -81,5 +85,4 @@ public class Plant {
public String toString() {
return String.format("{ @type = %1$s, id = %2$s, name = %3$s }", getClass().getSimpleName(), getId(), getName());
}
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright 2010-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.repository.sample;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.File;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* The PlantRepositoryTest class is a test suite of test cases testing the functionality behind PR #55 involving
* persisting application domain object/entities to multiple Regions in GemFire's Cache.
*
* @author John Blum
* @see org.junit.Test
* @see org.springframework.context.ConfigurableApplicationContext
* @since 1.4.0
* @link https://github.com/spring-projects/spring-data-gemfire/pull/55
*/
public class PlantRepositoryTest {
private static final String APPLICATION_CONTEXT_CONFIG_LOCATION = String.format("%1$s%2$s%1$s%3$s",
File.separator, PlantRepositoryTest.class.getPackage().getName().replace('.', File.separatorChar),
"PlantRepositoryTest-context.xml");
@Test(expected = IllegalArgumentException.class)
public void storePlantHavingStringIdInPlantsRegionWithLongKey() {
try {
ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext(APPLICATION_CONTEXT_CONFIG_LOCATION);
context.getBean(PlantRepository.class);
}
// NOTE technically, the IllegalArgumentException for incompatible Region 'Key' and Entity ID is thrown
// when the Spring container starts up and the Repository beans are created.
catch (BeanCreationException expected) {
//expected.printStackTrace(System.err);
assertTrue(expected.getCause() instanceof IllegalArgumentException);
assertEquals(String.format("The Region referenced only supports keys of type [%1$s], but the entity to be stored has an id of type [%2$s]",
Long.class.getName(), String.class.getName()), expected.getCause().getMessage());
throw (IllegalArgumentException) expected.getCause();
}
}
}

View File

@@ -93,7 +93,8 @@ public class User implements Comparable<User> {
@Override
public boolean equals(final Object obj) {
if (obj == this) {
if (this == obj) {
return true;
}
@@ -113,9 +114,12 @@ public class User implements Comparable<User> {
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getEmail());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getUsername());
return hashValue;
}
@@ -123,5 +127,4 @@ public class User implements Comparable<User> {
public String toString() {
return getUsername();
}
}

View File

@@ -16,18 +16,16 @@
package org.springframework.data.gemfire.repository.support;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newUnsupportedOperationException;
import java.io.Serializable;
import java.util.Arrays;
@@ -36,285 +34,509 @@ import java.util.Collections;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.aop.framework.Advised;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.data.gemfire.repository.GemfireRepository;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.gemfire.util.RegionUtils;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryComposition;
/**
* Unit tests for {@link GemfireRepositoryFactory}.
*
* @author Oliver Gierke
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.springframework.data.gemfire.repository.support.GemfireRepositoryFactory
*/
@RunWith(MockitoJUnitRunner.class)
@SuppressWarnings("unused")
@SuppressWarnings("rawtypes")
public class GemfireRepositoryFactoryUnitTests {
@Rule
public ExpectedException exception = ExpectedException.none();
private GemfireMappingContext gemfireMappingContext = new GemfireMappingContext();
private GemfireMappingContext mappingContext;
@Mock
private Region<Object, Object> mockRegion;
private Region mockRegion;
@Mock
@SuppressWarnings("rawtypes")
private RegionAttributes mockRegionAttributes;
@SuppressWarnings("unchecked")
protected <K, V> Region<K, V> configureMockRegion(Region<K, V> mockRegion, String name,
Class<K> keyType, Class<V> valueType) {
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegion.getFullPath()).thenReturn(String.format("%1$s%2$s", Region.SEPARATOR, name));
when(mockRegion.getName()).thenReturn(name);
when(mockRegionAttributes.getKeyConstraint()).thenReturn(keyType);
when(mockRegionAttributes.getValueConstraint()).thenReturn(valueType);
return mockRegion;
}
@SuppressWarnings("unchecked")
protected <K, V> Region<K, V> mockRegion(String name, Class<K> keyType, Class<V> valueType) {
return configureMockRegion(mock(Region.class, name), name, keyType, valueType);
}
protected RepositoryMetadata mockRepositoryMetadata(final Class<?> domainType, final Class<?> idType,
final Class<?> repositoryInterface) {
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
when(mockRepositoryMetadata.getDomainType()).then(new Answer<Class<?>>() {
@Override public Class<?> answer(InvocationOnMock invocation) throws Throwable {
return domainType;
}
});
when(mockRepositoryMetadata.getIdType()).then(new Answer<Class<?>>() {
@Override public Class<?> answer(InvocationOnMock invocation) throws Throwable {
return idType;
}
});
when(mockRepositoryMetadata.getRepositoryInterface()).then(new Answer<Class<?>>() {
@Override public Class<?> answer(InvocationOnMock invocation) throws Throwable {
return repositoryInterface;
}
});
return mockRepositoryMetadata;
}
@Before
@SuppressWarnings("unchecked")
public void setup() {
configureMockRegion(mockRegion, "simple", Object.class, Object.class);
this.mappingContext = new GemfireMappingContext();
configureMockRegion(this.mockRegion, "simple", Object.class, Object.class);
}
@Test
public void constructGemfireRepositoryFactoryWithNullMappingContextThrowsIllegalArgumentException() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage("MappingContext must not be null");
new GemfireRepositoryFactory(Collections.<Region<?, ?>>emptyList(), null);
@SuppressWarnings("unchecked")
private <K, V> Region<K, V> mockRegion(String name, Class<K> keyType, Class<V> valueType) {
return configureMockRegion(this.mockRegion, name, keyType, valueType);
}
@Test
public void constructGemfireRepositoryFactoryWithNullRegionsThrowsIllegalArgumentException() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage("Regions must not be null");
@SuppressWarnings("unchecked")
private <K, V> Region<K, V> configureMockRegion(Region<K, V> mockRegion, String name,
Class<K> keyType, Class<V> valueType) {
new GemfireRepositoryFactory(null, gemfireMappingContext);
when(mockRegion.getAttributes()).thenReturn(this.mockRegionAttributes);
when(mockRegion.getFullPath()).thenReturn(RegionUtils.toRegionPath(name));
when(mockRegion.getName()).thenReturn(name);
when(this.mockRegionAttributes.getKeyConstraint()).thenReturn(keyType);
when(this.mockRegionAttributes.getValueConstraint()).thenReturn(valueType);
return mockRegion;
}
@Test
public void getRepositoryRegionNameFromRepositoryInterfaceWithRegionAnnotation() {
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>emptyList(), gemfireMappingContext);
private RepositoryMetadata mockRepositoryMetadata(Class<?> domainType, Class<?> idType,
Class<?> repositoryInterface) {
assertThat(gemfireRepositoryFactory.getRepositoryRegionName(PersonRepository.class),
is(equalTo("People")));
}
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
@Test
public void getRepositoryRegionNameFromRepositoryInterfaceWithoutRegionAnnotation() {
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>emptyList(), gemfireMappingContext);
when(mockRepositoryMetadata.getDomainType()).thenAnswer(invocation -> domainType);
when(mockRepositoryMetadata.getIdType()).thenAnswer(invocation -> idType);
when(mockRepositoryMetadata.getRepositoryInterface()).thenAnswer(invocation -> repositoryInterface);
assertThat(gemfireRepositoryFactory.getRepositoryRegionName(SampleCustomGemfireRepository.class),
is(nullValue(String.class)));
return mockRepositoryMetadata;
}
@Test
@SuppressWarnings("unchecked")
public void getTemplateReturnsGemfireTemplateForPeopleRegion() {
RepositoryMetadata mockRepositoryMetadata = mockRepositoryMetadata(Person.class, Long.class,
PersonRepository.class);
public void constructGemfireRepositoryFactorySuccessfully() {
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Collections.singletonList(this.mockRegion), this.mappingContext);
assertThat(repositoryFactory).isNotNull();
assertThat(repositoryFactory.getMappingContext()).isEqualTo(this.mappingContext);
assertThat(repositoryFactory.getRegions()).contains(this.mockRegion);
}
@Test(expected = IllegalArgumentException.class)
public void constructGemfireRepositoryFactoryWithNullMappingContextThrowsIllegalArgumentException() {
try {
new GemfireRepositoryFactory(Collections.emptyList(), null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("MappingContext is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test(expected = IllegalArgumentException.class)
public void constructGemfireRepositoryFactoryWithNullRegionsThrowsIllegalArgumentException() {
try {
new GemfireRepositoryFactory(null, this.mappingContext);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Regions are required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void getEntityRegionNameFromEntityRegionName() {
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Collections.emptyList(), this.mappingContext);
GemfirePersistentEntity<?> mockPersistentEntity = mock(GemfirePersistentEntity.class);
when(mockPersistentEntity.getRegionName()).thenReturn("MockRegionName");
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
assertThat(repositoryFactory.getEntityRegionName(mockRepositoryMetadata, mockPersistentEntity))
.isEqualTo("MockRegionName");
verify(mockPersistentEntity, times(1)).getRegionName();
verify(mockPersistentEntity, never()).getType();
verifyZeroInteractions(mockRepositoryMetadata);
}
@Test
public void getEntityRegionNameFromEntityDomainType() {
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Collections.emptyList(), this.mappingContext);
GemfirePersistentEntity<?> mockPersistentEntity = mock(GemfirePersistentEntity.class);
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
when(mockPersistentEntity.getRegionName()).thenReturn(" ");
when(mockPersistentEntity.getType()).thenAnswer(invocation -> Person.class);
assertThat(repositoryFactory.getEntityRegionName(mockRepositoryMetadata, mockPersistentEntity))
.isEqualTo(Person.class.getSimpleName());
verify(mockPersistentEntity, times(1)).getRegionName();
verify(mockPersistentEntity, times(1)).getType();
verifyZeroInteractions(mockRepositoryMetadata);
}
@Test
public void getEntityRegionNameFromRepositoryMetadata() {
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Collections.emptyList(), this.mappingContext);
GemfirePersistentEntity<?> mockPersistentEntity = mock(GemfirePersistentEntity.class);
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
when(mockPersistentEntity.getRegionName()).thenReturn(" ");
when(mockPersistentEntity.getType()).thenReturn(null);
when(mockRepositoryMetadata.getDomainType()).thenAnswer(invocation -> Person.class);
assertThat(repositoryFactory.getEntityRegionName(mockRepositoryMetadata, mockPersistentEntity))
.isEqualTo(Person.class.getSimpleName());
verify(mockPersistentEntity, times(1)).getRegionName();
verify(mockPersistentEntity, times(1)).getType();
verify(mockRepositoryMetadata, times(1)).getDomainType();
}
@Test
public void getEntityRegionNameFromRepositoryMetadataWhenEntityIsNull() {
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Collections.emptyList(), this.mappingContext);
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
when(mockRepositoryMetadata.getDomainType()).thenAnswer(invocation -> Person.class);
assertThat(repositoryFactory.getEntityRegionName(mockRepositoryMetadata, null))
.isEqualTo(Person.class.getSimpleName());
verify(mockRepositoryMetadata, times(1)).getDomainType();
}
@Test
public void getRepositoryRegionNameFromRegionAnnotatedRepositoryInterface() {
GemfireRepositoryFactory gemfireRepositoryFactory =
new GemfireRepositoryFactory(Collections.emptyList(), this.mappingContext);
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
when(mockRepositoryMetadata.getRepositoryInterface()).thenAnswer(invocation -> PeopleRepository.class);
assertThat(gemfireRepositoryFactory.getRepositoryRegionName(mockRepositoryMetadata).orElse(null))
.isEqualTo("People");
verify(mockRepositoryMetadata, times(1)).getRepositoryInterface();
}
@Test
public void getRepositoryRegionNameFromRegionAnnotatedRepositoryInterfaceHavingNoValue() {
GemfireRepositoryFactory gemfireRepositoryFactory =
new GemfireRepositoryFactory(Collections.emptyList(), this.mappingContext);
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
when(mockRepositoryMetadata.getRepositoryInterface()).thenAnswer(invocation -> NonQualifiedRegionAnnotatedRepository.class);
assertThat(gemfireRepositoryFactory.getRepositoryRegionName(mockRepositoryMetadata).isPresent()).isFalse();
verify(mockRepositoryMetadata, times(1)).getRepositoryInterface();
}
@Test
public void getRepositoryRegionNameFromNonRegionAnnotatedRepositoryInterface() {
GemfireRepositoryFactory gemfireRepositoryFactory =
new GemfireRepositoryFactory(Collections.emptyList(), this.mappingContext);
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
when(mockRepositoryMetadata.getRepositoryInterface())
.thenAnswer(invocation -> TestGemfireRepository.class);
assertThat(gemfireRepositoryFactory.getRepositoryRegionName(mockRepositoryMetadata).isPresent()).isFalse();
verify(mockRepositoryMetadata, times(1)).getRepositoryInterface();
}
@Test
public void resolveRegionWithRepositoryMetadataAndRegionNamePath() {
RepositoryMetadata mockRepositoryMetadata =
mockRepositoryMetadata(Person.class, Long.class, PeopleRepository.class);
Region<?, ?> mockRegionOne = mockRegion("RegionOne", Person.class, Long.class);
Region<?, ?> mockRegionTwo = mockRegion("RegionTwo", Object.class, Long.class);
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Arrays.asList(mockRegionOne, mockRegionTwo), this.mappingContext);
assertThat(repositoryFactory.resolveRegion(mockRepositoryMetadata, mockRegionTwo.getName()))
.isEqualTo(mockRegionTwo);
assertThat(repositoryFactory.resolveRegion(mockRepositoryMetadata, mockRegionOne.getFullPath()))
.isEqualTo(mockRegionOne);
verifyZeroInteractions(mockRepositoryMetadata);
}
@Test(expected = IllegalStateException.class)
public void resolveRegionWithRepositoryMetadataAndNonExistingRegionNamePath() {
try {
RepositoryMetadata mockRepositoryMetadata =
mockRepositoryMetadata(Person.class, Long.class, PeopleRepository.class);
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Collections.emptyList(), this.mappingContext);
repositoryFactory.resolveRegion(mockRepositoryMetadata, "Test");
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage(GemfireRepositoryFactory.REGION_NOT_FOUND,
"Test", Person.class.getName());
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
@SuppressWarnings("unchecked")
public void newTemplateReturnsGemfireTemplateForPeopleRegion() {
RepositoryMetadata mockRepositoryMetadata =
mockRepositoryMetadata(Person.class, Long.class, PeopleRepository.class);
Region<Long, Person> mockPeopleRegion = mockRegion("People", Long.class, Person.class);
Iterable<Region<?, ?>> regions = Arrays.asList(mockRegion, mockPeopleRegion);
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Arrays.asList(this.mockRegion, mockPeopleRegion), mappingContext);
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
regions, gemfireMappingContext);
GemfireTemplate gemfireTemplate = repositoryFactory.newTemplate(mockRepositoryMetadata);
GemfireTemplate gemfireTemplate = gemfireRepositoryFactory.getTemplate(mockRepositoryMetadata);
assertThat(gemfireTemplate, is(notNullValue(GemfireTemplate.class)));
assertThat(gemfireTemplate.<Long, Person>getRegion(), is(equalTo(mockPeopleRegion)));
assertThat(gemfireTemplate).isNotNull();
assertThat(gemfireTemplate.getRegion()).isEqualTo(mockPeopleRegion);
verify(mockPeopleRegion, times(1)).getAttributes();
verify(mockPeopleRegion, times(1)).getFullPath();
verify(mockPeopleRegion, times(1)).getName();
verify(mockRegionAttributes, times(1)).getKeyConstraint();
verify(this.mockRegionAttributes, times(1)).getKeyConstraint();
verify(mockRepositoryMetadata, times(1)).getDomainType();
verify(mockRepositoryMetadata, times(1)).getIdType();
verify(mockRepositoryMetadata, times(1)).getRepositoryInterface();
verifyNoMoreInteractions(mockRepositoryMetadata);
}
@Test
public void getTemplateReturnsGemfireTemplateForSimpleRegion() {
RepositoryMetadata mockRepositoryMetadata = mockRepositoryMetadata(Person.class, Long.class,
SampleCustomGemfireRepository.class);
@SuppressWarnings("unchecked")
public void newTemplateReturnsGemfireTemplateForSimpleRegion() {
Iterable<Region<?, ?>> regions = Collections.<Region<?, ?>>singleton(mockRegion);
RepositoryMetadata mockRepositoryMetadata =
mockRepositoryMetadata(Person.class, Long.class, TestGemfireRepository.class);
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
regions, gemfireMappingContext);
GemfireRepositoryFactory gemfireRepositoryFactory =
new GemfireRepositoryFactory(Collections.singleton(this.mockRegion), this.mappingContext);
GemfireTemplate gemfireTemplate = gemfireRepositoryFactory.getTemplate(mockRepositoryMetadata);
GemfireTemplate gemfireTemplate = gemfireRepositoryFactory.newTemplate(mockRepositoryMetadata);
assertThat(gemfireTemplate, is(notNullValue(GemfireTemplate.class)));
assertThat(gemfireTemplate.getRegion(), is(equalTo(mockRegion)));
assertThat(gemfireTemplate).isNotNull();
assertThat(gemfireTemplate.getRegion()).isEqualTo(this.mockRegion);
verify(this.mockRegion, times(1)).getAttributes();
verify(this.mockRegionAttributes, times(1)).getKeyConstraint();
verify(mockRepositoryMetadata, times(1)).getDomainType();
verify(mockRepositoryMetadata, times(1)).getIdType();
verify(mockRepositoryMetadata, times(1)).getRepositoryInterface();
verifyNoMoreInteractions(mockRepositoryMetadata);
}
@Test
public void getTemplateThrowsIllegalArgumentExceptionForIncompatibleRegionKeyTypeAndRepositoryIdType() {
RepositoryMetadata mockRepositoryMetadata = mockRepositoryMetadata(Person.class, Long.class,
PersonRepository.class);
@Test(expected = IllegalArgumentException.class)
public void newTemplateWithIncompatibleRegionKeyTypeAndRepositoryIdTypeThrowsIllegalArgumentException() {
Region<String, Person> mockPeopleRegion = mockRegion("People", String.class, Person.class);
RepositoryMetadata mockRepositoryMetadata =
mockRepositoryMetadata(Person.class, Long.class, PeopleRepository.class);
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>singleton(mockPeopleRegion), gemfireMappingContext);
Region<Integer, Person> mockPeopleRegion = mockRegion("People", Integer.class, Person.class);
GemfireRepositoryFactory gemfireRepositoryFactory =
new GemfireRepositoryFactory(Collections.singleton(mockPeopleRegion), this.mappingContext);
try {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(String.format(
"The Region referenced only supports keys of type [%1$s], but the entity to be stored has an id of type [%2$s]",
String.class.getName(), Long.class.getName()));
gemfireRepositoryFactory.newTemplate(mockRepositoryMetadata);
}
catch (IllegalArgumentException expected) {
gemfireRepositoryFactory.getTemplate(mockRepositoryMetadata);
assertThat(expected).hasMessage(GemfireRepositoryFactory.REGION_REPOSITORY_ID_TYPE_MISMATCH,
"/People", Integer.class.getName(), PeopleRepository.class.getName(), Long.class.getName());
assertThat(expected).hasNoCause();
throw expected;
}
finally {
verify(mockPeopleRegion, times(1)).getAttributes();
verify(mockPeopleRegion, atLeastOnce()).getFullPath();
verify(this.mockRegionAttributes, times(1)).getKeyConstraint();
verify(mockRepositoryMetadata, times(1)).getDomainType();
verify(mockRepositoryMetadata, times(1)).getIdType();
verify(mockPeopleRegion, times(1)).getAttributes();
verify(mockPeopleRegion, times(1)).getFullPath();
verify(mockPeopleRegion, times(1)).getName();
verify(mockRegionAttributes, times(1)).getKeyConstraint();
verify(mockRepositoryMetadata, times(2)).getRepositoryInterface();
verifyNoMoreInteractions(mockRepositoryMetadata);
}
}
@Test
public void getTemplateThrowsIllegalStateExceptionForRegionNotFound() {
RepositoryMetadata mockRepositoryMetadata = mockRepositoryMetadata(Person.class, Long.class,
PersonRepository.class);
@Test(expected = IllegalArgumentException.class)
public void newTemplateWithIncompatibleRepositoryIdTypeAndEntityIdTypeThrowsIllegalArgumentException() {
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>singleton(mockRegion), gemfireMappingContext);
RepositoryMetadata mockRepositoryMetadata =
mockRepositoryMetadata(Person.class, Integer.class, PeopleIntegerRepository.class);
Region<String, Person> mockPeopleRegion = mockRegion("People", null, null);
GemfireRepositoryFactory gemfireRepositoryFactory =
new GemfireRepositoryFactory(Collections.singleton(mockPeopleRegion), this.mappingContext);
try {
exception.expect(IllegalStateException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(String.format(
"No Region [People] was found for domain class [%s]; Make sure you have configured a GemFire Region of that name in your application context",
Person.class.getName()));
gemfireRepositoryFactory.newTemplate(mockRepositoryMetadata);
}
catch (IllegalArgumentException expected) {
gemfireRepositoryFactory.getTemplate(mockRepositoryMetadata);
assertThat(expected).hasMessage(GemfireRepositoryFactory.REPOSITORY_ENTITY_ID_TYPE_MISMATCH,
PeopleIntegerRepository.class.getName(), Integer.class.getName(), Person.class.getName(),
Long.class.getName());
assertThat(expected).hasNoCause();
throw expected;
}
finally {
verify(mockPeopleRegion, times(1)).getAttributes();
verify(this.mockRegionAttributes, times(1)).getKeyConstraint();
verify(mockRepositoryMetadata, times(1)).getDomainType();
verify(mockRepositoryMetadata, times(1)).getIdType();
verify(mockRepositoryMetadata, times(2)).getRepositoryInterface();
verifyNoMoreInteractions(mockRepositoryMetadata);
}
}
@Test(expected = IllegalStateException.class)
@SuppressWarnings("unchecked")
public void newTemplateWithNonExistingRegionThrowsIllegalStateException() {
RepositoryMetadata mockRepositoryMetadata =
mockRepositoryMetadata(Person.class, Long.class, PeopleRepository.class);
GemfireRepositoryFactory gemfireRepositoryFactory =
new GemfireRepositoryFactory(Collections.singleton(this.mockRegion), this.mappingContext);
try {
gemfireRepositoryFactory.newTemplate(mockRepositoryMetadata);
}
catch (IllegalStateException expected) {
assertThat(expected).hasMessage(GemfireRepositoryFactory.REGION_NOT_FOUND,
"People", Person.class.getName(), PeopleRepository.class.getName());
assertThat(expected).hasNoCause();
throw expected;
}
finally {
verify(mockRepositoryMetadata, times(2)).getDomainType();
verify(mockRepositoryMetadata, never()).getIdType();
verify(mockRegion, times(1)).getFullPath();
verify(mockRegion, times(1)).getName();
verifyZeroInteractions(mockRegionAttributes);
verify(mockRepositoryMetadata, times(2)).getRepositoryInterface();
}
}
/**
* @link https://jira.spring.io/browse/SGF-112
* @link <a href="https://jira.spring.io/browse/SGF-112">Repositories should reject PagingAndSortingRepository and Pageable parameters</a>
*/
@Test
@Test(expected = IllegalStateException.class)
@SuppressWarnings("unchecked")
public void rejectsInterfacesExtendingPagingAndSortingRepository() {
exception.expect(IllegalStateException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(startsWith("Pagination is not supported by GemFire Repositories"));
GemfireRepositoryFactory repositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>singletonList(mockRegion), new GemfireMappingContext());
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Collections.singletonList(this.mockRegion), new GemfireMappingContext());
repositoryFactory.getRepository(SamplePagingAndSortingRepository.class);
try {
repositoryFactory.getRepository(SamplePagingAndSortingRepository.class);
}
catch (IllegalStateException expected) {
assertThat(expected).hasMessageStartingWith("Pagination is not supported by GemFire Repositories");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
@SuppressWarnings("unchecked")
public void usesConfiguredRepositoryBaseClass() {
GemfireRepositoryFactory repositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>singletonList(mockRegion), new GemfireMappingContext());
repositoryFactory.setRepositoryBaseClass(CustomBaseRepository.class);
GemfireRepositoryFactory repositoryFactory =
new GemfireRepositoryFactory(Collections.singletonList(this.mockRegion), this.mappingContext);
GemfireRepository<?, ?> gemfireRepository = repositoryFactory.getRepository(SampleCustomGemfireRepository.class,
new SampleCustomRepositoryImpl());
repositoryFactory.setRepositoryBaseClass(TestCustomBaseRepository.class);
assertThat(((Advised) gemfireRepository).getTargetClass(), is(equalTo((Class) CustomBaseRepository.class)));
GemfireRepository<?, ?> gemfireRepository =
repositoryFactory.getRepository(TestGemfireRepository.class,
RepositoryComposition.RepositoryFragments.just(new TestCustomRepositoryImpl()));
assertThat(((Advised) gemfireRepository).getTargetClass()).isEqualTo(TestCustomBaseRepository.class);
}
interface SamplePagingAndSortingRepository extends PagingAndSortingRepository<Person, Long> {
}
static class CustomBaseRepository<T, ID extends Serializable> extends SimpleGemfireRepository<T, ID> {
static class TestCustomBaseRepository<T, ID extends Serializable> extends SimpleGemfireRepository<T, ID> {
public CustomBaseRepository(GemfireTemplate template, EntityInformation<T, ID> entityInformation) {
public TestCustomBaseRepository(GemfireTemplate template, EntityInformation<T, ID> entityInformation) {
super(template, entityInformation);
}
}
interface SampleCustomRepository<T> {
interface TestCustomRepository<T> {
@SuppressWarnings("unused")
void doCustomUpdate(T entity);
}
class SampleCustomRepositoryImpl<T> implements SampleCustomRepository<T> {
class TestCustomRepositoryImpl<T> implements TestCustomRepository<T> {
@Override
public void doCustomUpdate(final T entity) {
throw new UnsupportedOperationException("Not Implemented");
public void doCustomUpdate(T entity) {
throw newUnsupportedOperationException("Not Implemented");
}
}
interface SampleCustomGemfireRepository extends GemfireRepository<Person, Long>, SampleCustomRepository<Person> {
}
interface TestGemfireRepository extends GemfireRepository<Person, Long>, TestCustomRepository<Person> { }
@org.springframework.data.gemfire.mapping.annotation.Region("People")
interface PersonRepository extends GemfireRepository<Person, Long> {
}
interface PeopleRepository extends GemfireRepository<Person, Long> { }
@org.springframework.data.gemfire.mapping.annotation.Region("People")
interface PeopleIntegerRepository extends GemfireRepository<Person, Integer> { }
@org.springframework.data.gemfire.mapping.annotation.Region
interface NonQualifiedRegionAnnotatedRepository extends GemfireRepository<Person, Long> { }
}

View File

@@ -17,8 +17,6 @@
package org.springframework.data.gemfire.util;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -35,10 +33,11 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.data.gemfire.test.support.MapBuilder;
/**
* Unit tests for {@link CollectionUtils}.
@@ -59,9 +58,6 @@ import org.junit.rules.ExpectedException;
*/
public class CollectionUtilsUnitTests {
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void addAllIterableElementsToList() {
@@ -88,14 +84,19 @@ public class CollectionUtilsUnitTests {
assertThat(target).contains(1, 2, 3, 4, 5);
}
@Test
@Test(expected = IllegalArgumentException.class)
public void addIterableToNullCollection() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage("Collection is required");
try {
CollectionUtils.addAll(null, Collections.emptySet());
}
catch (IllegalArgumentException expected) {
CollectionUtils.addAll(null, Collections.emptySet());
assertThat(expected).hasMessage("Collection is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
@@ -185,6 +186,11 @@ public class CollectionUtilsUnitTests {
assertThat(CollectionUtils.containsAny(null, 1)).isFalse();
}
@Test
public void containsAnyWithNullCollectionAndNullArrayIsFalse() {
assertThat(CollectionUtils.containsAny(null, (Object[]) null)).isFalse();
}
@Test
public void emptyIterableReturnsEmptyIterable() {
@@ -197,25 +203,20 @@ public class CollectionUtilsUnitTests {
@Test
@SuppressWarnings("unchecked")
public void iterableEnumeration() {
public void iterableOfEnumeration() {
Enumeration<String> mockEnumeration = mock(Enumeration.class, "MockEnumeration");
Enumeration<Object> mockEnumeration = mock(Enumeration.class, "MockEnumeration");
when(mockEnumeration.hasMoreElements()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
when(mockEnumeration.nextElement()).thenReturn("zero").thenReturn("one").thenReturn("two")
when(mockEnumeration.nextElement()).thenReturn(1).thenReturn(2).thenReturn(3)
.thenThrow(new NoSuchElementException("Enumeration exhausted"));
Iterable<String> iterable = CollectionUtils.iterable(mockEnumeration);
Iterable<Object> iterable = CollectionUtils.iterable(mockEnumeration);
assertThat(iterable).isNotNull();
List<String> actualList = new ArrayList<String>(3);
for (String element : iterable) {
actualList.add(element);
}
assertThat(actualList).isEqualTo(Arrays.asList("zero", "one", "two"));
//assertThat(iterable).containsExactly(1, 2, 3);
assertThat(StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toSet()))
.containsExactly(1, 2, 3);
verify(mockEnumeration, times(4)).hasMoreElements();
verify(mockEnumeration, times(3)).nextElement();
@@ -223,30 +224,93 @@ public class CollectionUtilsUnitTests {
@Test
@SuppressWarnings("unchecked")
public void iterableIterator() {
public void iterableOfSingleEnumeration() {
Iterator<String> mockIterator = mock(Iterator.class, "MockIterator");
Enumeration<Object> mockEnumeration = mock(Enumeration.class);
when(mockEnumeration.hasMoreElements()).thenReturn(true).thenReturn(false);
when(mockEnumeration.nextElement()).thenReturn(1)
.thenThrow(new NoSuchElementException("Enumeration exhausted"));
Iterable<Object> iterable = CollectionUtils.iterable(mockEnumeration);
assertThat(iterable).isNotNull();
//assertThat(iterable).containsExactly(1);
assertThat(StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toSet()))
.containsExactly(1);
verify(mockEnumeration, times(2)).hasMoreElements();
verify(mockEnumeration, times(1)).nextElement();
}
@Test
@SuppressWarnings("unchecked")
public void iterableOfNullEnumeration() {
Iterable<?> iterable = CollectionUtils.iterable((Enumeration<?>) null);
assertThat(iterable).isNotNull();
assertThat(iterable).isEmpty();
}
@Test
@SuppressWarnings("unchecked")
public void iterableOfIterator() {
Iterator<Object> mockIterator = mock(Iterator.class, "MockIterator");
when(mockIterator.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
when(mockIterator.next()).thenReturn("zero").thenReturn("one").thenReturn("two")
when(mockIterator.next()).thenReturn(1).thenReturn(2).thenReturn(3)
.thenThrow(new NoSuchElementException("Iterator exhausted"));
Iterable<String> iterable = CollectionUtils.iterable(mockIterator);
Iterable<Object> iterable = CollectionUtils.iterable(mockIterator);
assertThat(iterable).isNotNull();
List<String> actualList = new ArrayList<String>(3);
Set<Object> set = new HashSet<>();
for (String element : iterable) {
actualList.add(element);
}
iterable.forEach(set::add);
assertThat(actualList).containsAll(Arrays.asList("zero", "one", "two"));
assertThat(set).hasSize(3);
assertThat(set).containsExactly(1, 2, 3);
verify(mockIterator, times(4)).hasNext();
verify(mockIterator, times(3)).next();
}
@Test
@SuppressWarnings("unchecked")
public void iterableOfSingleIterator() {
Iterator<Object> mockIterator = mock(Iterator.class, "MockIterator");
when(mockIterator.hasNext()).thenReturn(true).thenReturn(false);
when(mockIterator.next()).thenReturn(1).thenThrow(new NoSuchElementException("Iterator exhausted"));
Iterable<Object> iterable = CollectionUtils.iterable(mockIterator);
assertThat(iterable).isNotNull();
Set<Object> set = new HashSet<>();
iterable.forEach(set::add);
assertThat(set).hasSize(1);
assertThat(set).containsExactly(1);
verify(mockIterator, times(2)).hasNext();
verify(mockIterator, times(1)).next();
}
@Test
public void iterableOfNullIterator() {
Iterable<?> iterable = CollectionUtils.iterable((Iterator<?>) null);
assertThat(iterable).isNotNull();
assertThat(iterable).isEmpty();
}
@Test
public void nullSafeCollectionWithNonNullCollection() {
@@ -264,6 +328,23 @@ public class CollectionUtilsUnitTests {
assertThat(collection.isEmpty()).isTrue();
}
@Test
public void nullSafeEnumerationWithNonNullEnumeration() {
Enumeration<?> mockEnumeration = mock(Enumeration.class);
assertThat(CollectionUtils.nullSafeEnumeration(mockEnumeration)).isSameAs(mockEnumeration);
}
@Test
public void nullSafeEnumerationWithNullEnumeration() {
Enumeration<?> enumeration = CollectionUtils.nullSafeEnumeration(null);
assertThat(enumeration).isNotNull();
assertThat(enumeration.hasMoreElements()).isFalse();
}
@Test
@SuppressWarnings("unchecked")
public void nullSafeIterableWithNonNullIterable() {
@@ -340,6 +421,23 @@ public class CollectionUtilsUnitTests {
assertThat(CollectionUtils.nullSafeIterable((Iterable<?>) null, null)).isNull();
}
@Test
public void nullSafeIteratorWithNonNullIterator() {
Iterator<?> mockIterator = mock(Iterator.class);
assertThat(CollectionUtils.nullSafeIterator(mockIterator)).isSameAs(mockIterator);
}
@Test
public void nullSafeIteratorWithNullIterator() {
Iterator<?> iterator = CollectionUtils.nullSafeIterator(null);
assertThat(iterator).isNotNull();
assertThat(iterator).isEmpty();
}
@Test
public void nullSafeListWithNonNullList() {
@@ -391,18 +489,97 @@ public class CollectionUtilsUnitTests {
assertThat(set.isEmpty()).isTrue();
}
@Test
public void nullSafeIsEmptyCollectionWithNonNulNonEmptyCollectionReturnsFalse() {
assertThat(CollectionUtils.nullSafeIsEmpty(Collections.singleton(1))).isFalse();
assertThat(CollectionUtils.nullSafeIsEmpty(Collections.singletonList(1))).isFalse();
}
@Test
public void nullSafeIsEmptyCollectionWithEmptyCollectionReturnsTrue() {
assertThat(CollectionUtils.isEmpty(Collections.emptyList())).isTrue();
assertThat(CollectionUtils.isEmpty(Collections.emptySet())).isTrue();
}
@Test
public void nullSafeIsEmptyCollectionWithNullCollectionReturnsTrue() {
assertThat(CollectionUtils.isEmpty((Collection<?>) null)).isTrue();
}
@Test
public void nullSafeIsEmptyMapWithNonNullNonEmptyMapReturnsFalse() {
assertThat(CollectionUtils.isEmpty(Collections.singletonMap("key", "value"))).isFalse();
}
@Test
public void nullSafeIsEmptyMapWithEmptyMapReturnsTrue() {
assertThat(CollectionUtils.isEmpty(Collections.emptyMap())).isTrue();
}
@Test
public void nullSafeIsEmptyMapWithNullMapReturnsTrue() {
assertThat(CollectionUtils.isEmpty((Map<?, ?>) null)).isTrue();
}
@Test
public void nullSafeCollectionSizeWithNonNullNonEmptyCollectionReturnsSize() {
assertThat(CollectionUtils.nullSafeSize(Collections.singleton(1))).isEqualTo(1);
assertThat(CollectionUtils.nullSafeSize(Collections.singletonList(1))).isEqualTo(1);
}
@Test
public void nullSafeCollectionSizeWithEmptyCollectionReturnsZero() {
assertThat(CollectionUtils.nullSafeSize(Collections.emptyList())).isZero();
assertThat(CollectionUtils.nullSafeSize(Collections.emptySet())).isZero();
}
@Test
public void nullSafeCollectionSizeWithNullCollectionReturnsZero() {
assertThat(CollectionUtils.nullSafeSize((Collection<?>) null)).isZero();
}
@Test
public void nullSafeMapSizeWithNonNullNonEmptyMapReturnsSize() {
assertThat(CollectionUtils.nullSafeSize(Collections.singletonMap("key", "value"))).isEqualTo(1);
}
@Test
public void nullSafeMapSizeWithEmptyMapReturnsZero() {
assertThat(CollectionUtils.nullSafeSize(Collections.emptyMap())).isZero();
}
@Test
public void nullSafeMapSizeWithNullMapReturnsZero() {
assertThat(CollectionUtils.nullSafeSize((Map<?, ?>) null)).isZero();
}
@Test
public void sortIsSuccessful() {
List<Integer> list = new ArrayList<Integer>(Arrays.asList(2, 3, 1));
List<Integer> list = new ArrayList<>(Arrays.asList(2, 3, 1));
List<Integer> sortedList = CollectionUtils.sort(list);
assertThat(sortedList).isSameAs(list);
assertThat(sortedList).isEqualTo(Arrays.asList(1, 2, 3));
}
@Test(expected = IllegalArgumentException.class)
public void sortWithNullListThrowsIllegalArgumentException() {
try {
CollectionUtils.sort(null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("List is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void subListFromListWithIndexesReturnsSubList() {
public void subListOfListWithIndexesReturnsSubList() {
List<Integer> list = Arrays.asList(0, 1, 2, 3);
List<Integer> subList = CollectionUtils.subList(list, 1, 3);
@@ -413,8 +590,13 @@ public class CollectionUtilsUnitTests {
assertThat(subList).containsAll(Arrays.asList(1, 3));
}
@Test(expected = IndexOutOfBoundsException.class)
public void subListOfListWithInvalidIndexThrowsIndexOutOfBoundsException() {
CollectionUtils.subList(Arrays.asList(0, 1, 2), 1, 3);
}
@Test
public void subListFromListWithNoIndexesReturnsEmptyList() {
public void subListOfListWithNoIndexesReturnsEmptyList() {
List<Integer> subList = CollectionUtils.subList(Arrays.asList(0, 1, 2));
@@ -422,18 +604,59 @@ public class CollectionUtilsUnitTests {
assertThat(subList.isEmpty()).isTrue();
}
@Test(expected = IndexOutOfBoundsException.class)
public void subListFromListWithInvalidIndexThrowsIndexOutOfBoundsException() {
CollectionUtils.subList(Arrays.asList(0, 1, 2), 1, 3);
@Test(expected = IllegalArgumentException.class)
public void subListOfNullListThrowsIllegalArgumentException() {
try {
CollectionUtils.subList(null, 1, 2, 3);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("List is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void subListWithNullSourceListThrowsIllegalArgumentException() {
public void toStringOfMultiEntryMap() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage("List is required");
Map<String, String> map = MapBuilder.<String, String>newMapBuilder()
.put("keyOne", "valueOne")
.put("keyTwo", "valueTwo")
.build();
CollectionUtils.subList(null, 1, 2, 3);
String mapString = CollectionUtils.toString(map);
assertThat(mapString).isNotNull();
assertThat(mapString).isEqualTo("{\n\tkeyOne = valueOne,\n\tkeyTwo = valueTwo\n}");
}
@Test
public void toStringOfSingleEntryMap() {
String mapString = CollectionUtils.toString(Collections.singletonMap("key", "value"));
assertThat(mapString).isNotNull();
assertThat(mapString).isEqualTo("{\n\tkey = value\n}");
}
@Test
public void toStringOfEmptyMap() {
String mapString = CollectionUtils.toString(Collections.emptyMap());
assertThat(mapString).isNotNull();
assertThat(mapString).isEqualTo("{\n\n}");
}
@Test
public void toStringOfNullMap() {
String mapString = CollectionUtils.toString(null);
assertThat(mapString).isNotNull();
assertThat(mapString).isEqualTo("{\n\n}");
}
}