Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for regular expressions when specifying a field name #322

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;

/**
* Defines attributes used to identify fields.
Expand All @@ -39,7 +40,7 @@
@Value
public class FieldDefinition<T, F> {

private final String name;
private final Predicate<String> namePattern;

private final Class<F> type;

Expand All @@ -52,37 +53,37 @@ public class FieldDefinition<T, F> {
/**
* Create a new {@link FieldDefinition}.
*
* @param name the field name
* @param type the filed type
* @param namePattern to match field name
* @param type the field type
* @param clazz the declaring class type
*/
public FieldDefinition(String name, Class<F> type, Class<T> clazz) {
this(name, type, clazz, new HashSet<>());
public FieldDefinition(Predicate<String> namePattern, Class<F> type, Class<T> clazz) {
this(namePattern, type, clazz, new HashSet<>());
}

/**
* Create a new {@link FieldDefinition}.
*
* @param name the field name
* @param type the filed type
* @param namePattern to match field name
* @param type the field type
* @param clazz the declaring class type
* @param annotations annotations present on the field
*/
public FieldDefinition(String name, Class<F> type, Class<T> clazz, Set<Class <? extends Annotation>> annotations) {
this(name, type, clazz, annotations, null);
public FieldDefinition(Predicate<String> namePattern, Class<F> type, Class<T> clazz, Set<Class <? extends Annotation>> annotations) {
this(namePattern, type, clazz, annotations, null);
}

/**
* Create a new {@link FieldDefinition}.
*
* @param name the field name
* @param type the filed type
* @param namePattern to match field name
* @param type the field type
* @param clazz the declaring class type
* @param annotations annotations present on the field
* @param modifiers the field modifiers
*/
public FieldDefinition(String name, Class<F> type, Class<T> clazz, Set<Class <? extends Annotation>> annotations, Integer modifiers) {
this.name = name;
public FieldDefinition(Predicate<String> namePattern, Class<F> type, Class<T> clazz, Set<Class <? extends Annotation>> annotations, Integer modifiers) {
this.namePattern = namePattern;
this.type = type;
this.clazz = clazz;
this.annotations = annotations;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;

/**
* Builder for {@link FieldDefinition}.
Expand All @@ -37,6 +38,8 @@ public class FieldDefinitionBuilder {

private String name;

private Predicate<String> namingPattern;

private Class<?> type;

private Class<?> clazz;
Expand Down Expand Up @@ -65,6 +68,19 @@ public FieldDefinitionBuilder named(String name) {
return this;
}

/**
* Specify the pattern for field name.
*
* Taken into account only when name is not set
*
* @param patternName to match field name
* @return the configured {@link FieldDefinitionBuilder}
*/
public FieldDefinitionBuilder namingPattern(Predicate<String> patternName) {
this.namingPattern = patternName;
return this;
}

/**
* Specify the field type.
*
Expand Down Expand Up @@ -116,7 +132,11 @@ public FieldDefinitionBuilder hasModifiers(int modifiers) {
* @return a new {@link FieldDefinition}
*/
public FieldDefinition<?, ?> get() {
return new FieldDefinition<>(name, type, clazz, annotations, modifiers);
return new FieldDefinition<>(getNamingPattern(), type, clazz, annotations, modifiers);
}

private Predicate<String> getNamingPattern() {
return (name != null) ? s -> name.equals(s) : namingPattern;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Set;
import java.util.function.Predicate;

/**
* Base class for randomizer registries.
Expand All @@ -51,14 +52,14 @@ protected boolean hasType(final Field field, final Class<?> type) {
}

/**
* Check if a {@code field} has the given {@code name}.
* Check if a {@code field} matches given {@code namePattern}.
*
* @param field to check
* @param name of the field
* @return true if the field has the given name, false otherwise
* @param namePattern to match
* @return true if matches given pattern, false otherwise
*/
protected boolean hasName(final Field field, final String name) {
return name == null || field.getName().equals(name);
protected boolean matches(final Field field, final Predicate<String> namePattern) {
return namePattern == null || namePattern.test(field.getName());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void init(EnhancedRandomParameters parameters) {
@Override
public Randomizer<?> getRandomizer(Field field) {
for (FieldDefinition<?, ?> fieldDefinition : customFieldRandomizersRegistry.keySet()) {
if (hasName(field, fieldDefinition.getName()) &&
if (matches(field, fieldDefinition.getNamePattern()) &&
isDeclaredInClass(field, fieldDefinition.getClazz()) &&
hasType(field, fieldDefinition.getType()) &&
isAnnotatedWithOneOf(field, fieldDefinition.getAnnotations()) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void init(EnhancedRandomParameters parameters) {
@Override
public Randomizer<?> getRandomizer(Field field) {
for (FieldDefinition<?, ?> fieldDefinition : fieldDefinitions) {
if (hasName(field, fieldDefinition.getName()) &&
if (matches(field, fieldDefinition.getNamePattern()) &&
isDeclaredInClass(field, fieldDefinition.getClazz()) &&
hasType(field, fieldDefinition.getType()) &&
isAnnotatedWithOneOf(field, fieldDefinition.getAnnotations()) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,19 @@
*/
package io.github.benas.randombeans;

import static org.assertj.core.api.Assertions.assertThat;

import io.github.benas.randombeans.beans.Human;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import io.github.benas.randombeans.beans.Human;
import java.util.function.Predicate;
import java.util.regex.Pattern;

import static org.assertj.core.api.Assertions.assertThat;

public class FieldDefinitionBuilderTest {

private static final String NAME = "name";
private static final Predicate<String> NAME_PATTERN = Pattern.compile("[^i][a-z]").asPredicate();
private static final Class<String> TYPE = String.class;
private static final Class<Human> CLASS = Human.class;

Expand All @@ -48,8 +51,33 @@ public void testFieldDefinitionBuilding() {
FieldDefinition<?, ?> fieldDefinition = builder.named(NAME).ofType(TYPE).inClass(CLASS).get();

assertThat(fieldDefinition).isNotNull();
assertThat(fieldDefinition.getName()).isEqualTo(NAME);
assertThat(fieldDefinition.getNamePattern().test(NAME)).isTrue();
assertThat(fieldDefinition.getType()).isEqualTo(TYPE);
assertThat(fieldDefinition.getClazz()).isEqualTo(CLASS);
}

@Test
public void testFieldDefinitionBuildingUsingCustomPattern() {
FieldDefinition<?, ?> fieldDefinition = builder.namingPattern(NAME_PATTERN).ofType(TYPE).inClass(CLASS).get();

assertThat(fieldDefinition).isNotNull();
assertThat(fieldDefinition.getType()).isEqualTo(TYPE);
assertThat(fieldDefinition.getClazz()).isEqualTo(CLASS);

assertThat(fieldDefinition.getNamePattern().test(NAME)).isTrue();
assertThat(fieldDefinition.getNamePattern().test("not-name")).isTrue();
assertThat(fieldDefinition.getNamePattern().test("id")).isFalse();
}

@Test
public void testFieldDefinitionShouldFavorSimpleNameOverPattern() {
FieldDefinition<?, ?> fieldDefinition = builder
.named(NAME)
.namingPattern(NAME_PATTERN)
.ofType(TYPE).inClass(CLASS).get();

assertThat(fieldDefinition.getNamePattern().test(NAME)).isTrue();
assertThat(fieldDefinition.getNamePattern().test("id")).isFalse();
assertThat(fieldDefinition.getNamePattern().test("not-name")).isFalse();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ public void testSecondLevelCollectionExclusion() {
@Test
public void whenFieldIsExcluded_thenItsInlineInitializationShouldBeUsedAsIs() {
enhancedRandom = aNewEnhancedRandomBuilder()
.exclude(new FieldDefinition<>("myList", List.class, InlineInitializationBean.class))
.exclude(new FieldDefinition<>("myList"::equals, List.class, InlineInitializationBean.class))
.build();

InlineInitializationBean bean = enhancedRandom.nextObject(InlineInitializationBean.class);
Expand All @@ -287,7 +287,7 @@ public void whenFieldIsExcluded_thenItsInlineInitializationShouldBeUsedAsIs() {
@Test
public void whenFieldIsExcluded_thenItsInlineInitializationShouldBeUsedAsIs_EvenIfBeanHasNoPublicConstructor() {
enhancedRandom = aNewEnhancedRandomBuilder()
.exclude(new FieldDefinition<>("myList", List.class, InlineInitializationBeanPrivateConstructor.class))
.exclude(new FieldDefinition<>("myList"::equals, List.class, InlineInitializationBeanPrivateConstructor.class))
.build();

InlineInitializationBeanPrivateConstructor bean = enhancedRandom.nextObject(InlineInitializationBeanPrivateConstructor.class);
Expand Down