/*
* Copyright 2011-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.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.mapping.PropertyPath.*;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
/**
* Unit tests for {@link PropertyPath}.
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
@SuppressWarnings("unused")
public class PropertyPathUnitTests {
@Rule public ExpectedException exception = ExpectedException.none();
@Test
public void parsesSimplePropertyCorrectly() throws Exception {
PropertyPath reference = PropertyPath.from("userName", Foo.class);
assertThat(reference.hasNext()).isFalse();
assertThat(reference.toDotPath()).isEqualTo("userName");
assertThat(reference.getOwningType()).isEqualTo(ClassTypeInformation.from(Foo.class));
}
@Test
public void parsesPathPropertyCorrectly() throws Exception {
PropertyPath reference = PropertyPath.from("userName", Bar.class);
assertThat(reference.hasNext()).isTrue();
assertThat(reference.next()).isEqualTo(new PropertyPath("name", FooBar.class));
assertThat(reference.toDotPath()).isEqualTo("user.name");
}
@Test
public void prefersLongerMatches() throws Exception {
PropertyPath reference = PropertyPath.from("userName", Sample.class);
assertThat(reference.hasNext()).isFalse();
assertThat(reference.toDotPath()).isEqualTo("userName");
}
@Test
public void testname() throws Exception {
PropertyPath reference = PropertyPath.from("userName", Sample2.class);
assertThat(reference.getSegment()).isEqualTo("user");
assertThat(reference.hasNext()).isTrue();
assertThat(reference.next()).isEqualTo(new PropertyPath("name", FooBar.class));
}
@Test
public void prefersExplicitPaths() throws Exception {
PropertyPath reference = PropertyPath.from("user_name", Sample.class);
assertThat(reference.getSegment()).isEqualTo("user");
assertThat(reference.hasNext()).isTrue();
assertThat(reference.next()).isEqualTo(new PropertyPath("name", FooBar.class));
}
@Test
public void handlesGenericsCorrectly() throws Exception {
PropertyPath reference = PropertyPath.from("usersName", Bar.class);
assertThat(reference.getSegment()).isEqualTo("users");
assertThat(reference.isCollection()).isTrue();
assertThat(reference.hasNext()).isTrue();
assertThat(reference.next()).isEqualTo(new PropertyPath("name", FooBar.class));
}
@Test
public void handlesMapCorrectly() throws Exception {
PropertyPath reference = PropertyPath.from("userMapName", Bar.class);
assertThat(reference.getSegment()).isEqualTo("userMap");
assertThat(reference.isCollection()).isFalse();
assertThat(reference.hasNext()).isTrue();
assertThat(reference.next()).isEqualTo(new PropertyPath("name", FooBar.class));
}
@Test
public void handlesArrayCorrectly() throws Exception {
PropertyPath reference = PropertyPath.from("userArrayName", Bar.class);
assertThat(reference.getSegment()).isEqualTo("userArray");
assertThat(reference.isCollection()).isTrue();
assertThat(reference.hasNext()).isTrue();
assertThat(reference.next()).isEqualTo(new PropertyPath("name", FooBar.class));
}
@Test
public void handlesInvalidCollectionCompountTypeProperl() {
try {
PropertyPath.from("usersMame", Bar.class);
fail("Expected PropertyReferenceException!");
} catch (PropertyReferenceException e) {
assertThat(e.getPropertyName()).isEqualTo("mame");
assertThat(e.getBaseProperty()).isEqualTo(PropertyPath.from("users", Bar.class));
}
}
@Test
public void handlesInvalidMapValueTypeProperly() {
assertThatExceptionOfType(PropertyReferenceException.class)//
.isThrownBy(() -> PropertyPath.from("userMapMame", Bar.class))//
.matches(e -> e.getPropertyName().equals("mame"))//
.matches(e -> e.getBaseProperty().equals(PropertyPath.from("userMap", Bar.class)));
}
@Test
public void findsNested() {
PropertyPath from = PropertyPath.from("barUserName", Sample.class);
assertThat(from).isNotNull();
assertThat(from.getLeafProperty()).isEqualTo(PropertyPath.from("name", FooBar.class));
}
@Test // DATACMNS-45
public void handlesEmptyUnderscoresCorrectly() {
PropertyPath propertyPath = PropertyPath.from("_foo", Sample2.class);
assertThat(propertyPath.getSegment()).isEqualTo("_foo");
assertThat(propertyPath.getType()).isEqualTo(Foo.class);
propertyPath = PropertyPath.from("_foo__email", Sample2.class);
assertThat(propertyPath.toDotPath()).isEqualTo("_foo._email");
}
@Test
public void supportsDotNotationAsWell() {
PropertyPath propertyPath = PropertyPath.from("bar.userMap.name", Sample.class);
assertThat(propertyPath).isNotNull();
assertThat(propertyPath.getSegment()).isEqualTo("bar");
assertThat(propertyPath.getLeafProperty()).isEqualTo(PropertyPath.from("name", FooBar.class));
}
@Test
public void returnsCorrectIteratorForSingleElement() {
PropertyPath propertyPath = PropertyPath.from("userName", Foo.class);
Iterator<PropertyPath> iterator = propertyPath.iterator();
assertThat(iterator.hasNext()).isTrue();
assertThat(iterator.next()).isEqualTo(propertyPath);
assertThat(iterator.hasNext()).isFalse();
}
@Test
public void returnsCorrectIteratorForMultipleElement() {
PropertyPath propertyPath = PropertyPath.from("user.name", Bar.class);
Iterator<PropertyPath> iterator = propertyPath.iterator();
assertThat(iterator.hasNext()).isTrue();
assertThat(iterator.next()).isEqualTo(propertyPath);
assertThat(iterator.hasNext()).isTrue();
assertThat(iterator.next()).isEqualTo(propertyPath.next());
assertThat(iterator.hasNext()).isFalse();
}
@Test // DATACMNS-139
public void rejectsInvalidPropertyWithLeadingUnderscore() {
assertThatExceptionOfType(PropertyReferenceException.class)//
.isThrownBy(() -> PropertyPath.from("_id", Foo.class))//
.withMessageContaining("property _id");
}
@Test // DATACMNS-139
public void rejectsNestedInvalidPropertyWithLeadingUnderscore() {
assertThatExceptionOfType(PropertyReferenceException.class)//
.isThrownBy(() -> PropertyPath.from("_foo_id", Sample2.class))//
.withMessageContaining("property id");
}
@Test // DATACMNS-139
public void rejectsNestedInvalidPropertyExplictlySplitWithLeadingUnderscore() {
assertThatExceptionOfType(PropertyReferenceException.class)//
.isThrownBy(() -> PropertyPath.from("_foo__id", Sample2.class))//
.withMessageContaining("property _id");
}
@Test(expected = PropertyReferenceException.class) // DATACMNS 158
public void rejectsInvalidPathsContainingDigits() {
PropertyPath.from("PropertyThatWillFail4Sure", Foo.class);
}
@Test
public void rejectsInvalidProperty() {
assertThatExceptionOfType(PropertyReferenceException.class)//
.isThrownBy(() -> PropertyPath.from("_foo_id", Sample2.class))//
.matches(e -> e.getBaseProperty().getSegment().equals("_foo"));
}
@Test
public void samePathsEqual() {
PropertyPath left = PropertyPath.from("user.name", Bar.class);
PropertyPath right = PropertyPath.from("user.name", Bar.class);
PropertyPath shortPath = PropertyPath.from("user", Bar.class);
assertThat(left).isEqualTo(right);
assertThat(right).isEqualTo(left);
assertThat(left).isNotEqualTo(shortPath);
assertThat(shortPath).isNotEqualTo(left);
assertThat(left).isNotEqualTo(new Object());
}
@Test
public void hashCodeTests() {
PropertyPath left = PropertyPath.from("user.name", Bar.class);
PropertyPath right = PropertyPath.from("user.name", Bar.class);
PropertyPath shortPath = PropertyPath.from("user", Bar.class);
assertThat(left.hashCode()).isEqualTo(right.hashCode());
assertThat(left.hashCode()).isNotEqualTo(shortPath.hashCode());
}
@Test // DATACMNS-257
public void findsAllUppercaseProperty() {
PropertyPath path = PropertyPath.from("UUID", Foo.class);
assertThat(path).isNotNull();
assertThat(path.getSegment()).isEqualTo("UUID");
}
@Test // DATACMNS-257
public void findsNestedAllUppercaseProperty() {
PropertyPath path = PropertyPath.from("_fooUUID", Sample2.class);
assertThat(path).isNotNull();
assertThat(path.getSegment()).isEqualTo("_foo");
assertThat(path.hasNext()).isTrue();
assertThat(path.next().getSegment()).isEqualTo("UUID");
}
@Test // DATACMNS-381
public void exposesPreviouslyReferencedPathInExceptionMessage() {
exception.expect(PropertyReferenceException.class);
exception.expectMessage("bar"); // missing variable
exception.expectMessage("String"); // type
exception.expectMessage("Bar.user.name"); // previously referenced path
PropertyPath.from("userNameBar", Bar.class);
}
@Test(expected = IllegalArgumentException.class) // DATACMNS-387
public void rejectsNullSource() {
from(null, Foo.class);
}
@Test(expected = IllegalArgumentException.class) // DATACMNS-387
public void rejectsEmptySource() {
from("", Foo.class);
}
@Test(expected = IllegalArgumentException.class) // DATACMNS-387
public void rejectsNullClass() {
from("foo", (Class<?>) null);
}
@Test(expected = IllegalArgumentException.class) // DATACMNS-387
public void rejectsNullTypeInformation() {
from("foo", (TypeInformation<?>) null);
}
@Test // DATACMNS-546
public void returnsCompletePathIfResolutionFailedCompletely() {
exception.expect(PropertyReferenceException.class);
exception.expectMessage("somethingDifferent");
from("somethingDifferent", Foo.class);
}
@Test // DATACMNS-546
public void includesResolvedPathInExceptionMessage() {
exception.expect(PropertyReferenceException.class);
exception.expectMessage("fooName");
exception.expectMessage(FooBar.class.getSimpleName());
exception.expectMessage("Bar.user");
from("userFooName", Bar.class);
}
@Test // DATACMNS-703
public void includesPropertyHintsOnTypos() {
exception.expect(PropertyReferenceException.class);
exception.expectMessage("userName");
from("userAme", Foo.class);
}
@Test // DATACMNS-867
public void preservesUnderscoresForQuotedNames() {
PropertyPath path = from(Pattern.quote("var_name_with_underscore"), Foo.class);
assertThat(path).isNotNull();
assertThat(path.getSegment()).isEqualTo("var_name_with_underscore");
assertThat(path.hasNext()).isFalse();
}
private class Foo {
String userName;
String _email;
String UUID;
String var_name_with_underscore;
}
private class Bar {
private FooBar user;
private Set<FooBar> users;
private Map<String, FooBar> userMap;
private FooBar[] userArray;
}
private class FooBar {
private String name;
}
private class Sample {
private String userName;
private FooBar user;
private Bar bar;
}
private class Sample2 {
private String userNameWhatever;
private FooBar user;
private Foo _foo;
}
}