Skip to content

Commit

Permalink
Add methods to (randomly) generate lists of beans
Browse files Browse the repository at this point in the history
Issue: #4
Signed-off-by: Stefan Hechtl <[email protected]>
  • Loading branch information
stefanhechtltng committed Mar 18, 2022
1 parent cba6521 commit 18a70ee
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 1 deletion.
1 change: 1 addition & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
dependencies {
testImplementation dependency.junit_jupiter_api
testImplementation dependency.lombok

testRuntimeOnly dependency.junit_jupiter_engine
}
Expand Down
134 changes: 133 additions & 1 deletion core/src/main/java/com/tngtech/valueprovider/ValueProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.time.LocalTime;
import java.time.Month;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
Expand Down Expand Up @@ -735,7 +736,8 @@ public <T extends Enum<T>> Set<T> someOf(Class<T> enumClass, int numberOfElement
* @param elements the elements to draw from.
* @return the drawn elements (none / some / all).
*/
@SafeVarargs final public <T> Collection<T> someOf(T... elements) {
@SafeVarargs
final public <T> Collection<T> someOf(T... elements) {
return someOf(asList(elements));
}

Expand Down Expand Up @@ -829,6 +831,136 @@ public final <T> T oneOfExcluding(Iterable<T> elements, T... elementsToExclude)
return oneOf(allElements);
}

/**
* Generates a {@link List} of &lt;T&gt; (by means of {@code generator}) and includes {@code containedElements} in the {@link List}.
* <p>
* Example:
* <pre>
* static class MyBeanTestData {
* public static MyBean myBean(ValueProvider valueProvider) {
* // builds and returns your bean
* }
* }
*
* ValueProvider vp = ValueProviderFactory.createRandomValueProvider();
* vp.listOfContaining(MyBeanTestData::myBean, myBean(), myBean(), myBean()); // -> List[myBean_1, myBean_2, myBean_random, myBean_3, myBean_random]
* </pre>
* </p>
*
* @param generator a generator {@link Function} to generate T given a {@link ValueProvider}.
* @param containedElements elements that should be contained in the generated list.
*
* @return the generated {@link List}.
*
* @see #listOf(Function)
*/
@SafeVarargs
public final <T, V extends ValueProvider> List<T> listOfContaining(Function<V, T> generator, T... containedElements) {
return listOfContaining(generator, Arrays.asList(containedElements));
}

/**
* see {@link #listOfContaining(Function, Object[])}
*/
public final <T, V extends ValueProvider> List<T> listOfContaining(Function<V, T> generator, Collection<T> containedElements) {
int maxNumberOfRandomElements = maxNumberOfRandomElements(containedElements);

List<T> generatedElements = new ArrayList<>();
for (T containedValue : containedElements) {
generatedElements.addAll(listOf(intNumber(0, maxNumberOfRandomElements), generator));
generatedElements.add(containedValue);
}
generatedElements.addAll(listOf(intNumber(0, maxNumberOfRandomElements), generator));
return generatedElements;
}

private <T> int maxNumberOfRandomElements(Collection<T> containedElements) {
if (containedElements.size() == 0) {
return 5;
}
if (containedElements.size() == 1) {
return 2;
}
return 1;
}

/**
* Generates a {@link List} of &lt;T&gt; (by means of {@code generator}). Ensures that the {@link List} contains at least one element.
* <p>
* Example:
* <pre>
* static class MyBeanTestData {
* public static MyBean myBean(ValueProvider valueProvider) {
* // builds and returns your bean
* }
* }
*
* ValueProvider vp = ValueProviderFactory.createRandomValueProvider();
* vp.nonEmptyListOf(MyBeanTestData::myBean); // -> List[myBean_generated_1, myBean_generated_2]
* </pre>
* </p>
*
* @param generator a generator {@link Function} to generate T given a {@link ValueProvider}.
*
* @return the generated {@link List}.
*/
public <T, V extends ValueProvider> List<T> nonEmptyListOf(Function<V, T> generator) {
return listOf(intNumber(1, 5), generator);
}

/**
* Generates a {@link List} of &lt;T&gt; (by means of {@code generator}). Might return the empty list.
* <p>
* Example:
* <pre>
* static class MyBeanTestData {
* public static MyBean myBean(ValueProvider valueProvider) {
* // builds and returns your bean
* }
* }
*
* ValueProvider vp = ValueProviderFactory.createRandomValueProvider();
* vp.listOf(MyBeanTestData::myBean); // -> List[myBean_generated_1, myBean_generated_2]
* vp.listOf(MyBeanTestData::myBean); // -> List[]
* </pre>
* </p>
*
* @param generator a generator {@link Function} to generate T given a {@link ValueProvider}.
*
* @return the generated {@link List}.
*/
public <T, V extends ValueProvider> List<T> listOf(Function<V, T> generator) {
return listOf(intNumber(0, 5), generator);
}

/**
* Generates a {@link List} of &lt;T&gt; (by means of {@code generator}). Containing exactly {@code numberOfElements} elements.
* <p>
* Example:
* <pre>
* static class MyBeanTestData {
* public static MyBean myBean(ValueProvider valueProvider) {
* // builds and returns your bean
* }
* }
*
* ValueProvider vp = ValueProviderFactory.createRandomValueProvider();
* vp.listOf(4, MyBeanTestData::myBean); // -> List[myBean_generated_1, myBean_generated_2, myBean_generated_3, myBean_generated_4]
* </pre>
* </p>
*
* @param generator a generator {@link Function} to generate T given a {@link ValueProvider}.
*
* @return the generated {@link List}.
*/
public <T, V extends ValueProvider> List<T> listOf(int numberOfElements, Function<V, T> generator) {
List<T> generatedElements = new ArrayList<>();
for (int i = 0; i < numberOfElements; i++) {
generatedElements.add(generator.apply((V) this));
}
return generatedElements;
}

/**
* Randomly draws true or false.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import java.util.stream.LongStream;
import java.util.stream.Stream;

import lombok.Data;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
Expand All @@ -32,6 +35,7 @@
import static com.tngtech.valueprovider.ValueProviderTest.MethodInvocation.assertDifferentResultAsFarAsPossible;
import static com.tngtech.valueprovider.ValueProviderTest.MethodInvocation.assertEqualResult;
import static com.tngtech.valueprovider.ValueProviderTest.MethodInvocation.invoke;
import static com.tngtech.valueprovider.ValueProviderTest.MyBeanTestData.myBeanContained;
import static com.tngtech.valueprovider.ValueProviderTest.TestEnum.EIGHT;
import static com.tngtech.valueprovider.ValueProviderTest.TestEnum.ELEVEN;
import static com.tngtech.valueprovider.ValueProviderTest.TestEnum.FIVE;
Expand Down Expand Up @@ -573,6 +577,44 @@ void someOf_should_return_duplicates_if_input_contains_duplicates() {
.hasSize(valueList.size());
}

@Test
void listOf_should_return_a_sensible_number_of_elements() {
// given
ValueProvider random = withRandomValues();

// when
List<MyBean> myBeans = random.listOf(MyBeanTestData::myBean);

// then
assertThat(myBeans).size().isLessThanOrEqualTo(5); // 5 is the default
}

@Test
void nonEmptyListOf_should_return_at_least_one_element() {
// given
ValueProvider random = withRandomValues();

// when
List<MyBean> myBeans = random.nonEmptyListOf(MyBeanTestData::myBean);

// then
assertThat(myBeans).size().isGreaterThanOrEqualTo(1);
assertThat(myBeans).size().isLessThanOrEqualTo(5); // 5 is the default
}

@Test
void listOfContaining_should_return_the_provided_elements_plus_some_randomly_generated_elements() {
// given
ValueProvider random = withRandomValues();

// when
List<MyBean> myBeans = random.listOfContaining(MyBeanTestData::myBean, myBeanContained(1), myBeanContained(2), myBeanContained(3));

// then
assertThat(myBeans).size().isLessThanOrEqualTo(7); // 3 contained beans + max. 1 random 'spacing' bean between each + max. 1 random bean at the beginning/end
assertThat(myBeans).contains(myBeanContained(1), myBeanContained(2), myBeanContained(3));
}

@Test
void ipV6Address_should_return_valid_IPv6_address() throws UnknownHostException {
ValueProvider random = withRandomValues();
Expand Down Expand Up @@ -673,4 +715,33 @@ private void assertBigDecimalNumberWithScale2(ValueProvider provider, Number min
.isGreaterThanOrEqualTo(new BigDecimal(min.doubleValue() - 0.01))
.isLessThanOrEqualTo(new BigDecimal(max.doubleValue() + 0.01));
}

static class MyBeanTestData {
public static MyBean myBean(ValueProvider valueProvider) {
return new MyBean("randomly generated");
}

public static MyBean myBeanContained(int counter) {
return new MyBean("contained" + counter);
}
}

@Data
static class MyBean {
String value;

public MyBean(String value) {
this.value = value;
}

@Override
public boolean equals(Object o) {
return EqualsBuilder.reflectionEquals(this, o, true);
}

@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, true);
}
}
}

0 comments on commit 18a70ee

Please sign in to comment.