diff --git a/core/build.gradle b/core/build.gradle
index 28551f0..09bfc2d 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -1,5 +1,7 @@
dependencies {
testImplementation dependency.junit_jupiter_api
+ testCompileOnly dependency.lombok
+ testAnnotationProcessor dependency.lombok
testRuntimeOnly dependency.junit_jupiter_engine
}
diff --git a/core/src/main/java/com/tngtech/valueprovider/ValueProvider.java b/core/src/main/java/com/tngtech/valueprovider/ValueProvider.java
index 51187c4..7a49ead 100644
--- a/core/src/main/java/com/tngtech/valueprovider/ValueProvider.java
+++ b/core/src/main/java/com/tngtech/valueprovider/ValueProvider.java
@@ -20,6 +20,7 @@
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import com.google.common.collect.Iterables;
@@ -34,6 +35,7 @@
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.SECONDS;
import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toList;
@SuppressWarnings("WeakerAccess")
public class ValueProvider {
@@ -829,6 +831,136 @@ public final T oneOfExcluding(Iterable elements, T... elementsToExclude)
return oneOf(allElements);
}
+ /**
+ * Generates a {@link List} of <T> (by means of {@code generator}) and includes {@code furtherContainedElements} in the {@link List}.
+ *
+ * Example:
+ *
+ * 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]
+ *
+ *
+ *
+ * @param generator a generator {@link Function} to generate T given a {@link ValueProvider}.
+ * @param firstContainedElement first element that should be contained in the generated list.
+ * @param furtherContainedElements further elements that should be contained in the generated list.
+ *
+ * @return the generated {@link List}.
+ *
+ * @see #listOf(Function)
+ */
+ @SafeVarargs
+ public final List listOfContaining(Function generator, T firstContainedElement, T... furtherContainedElements) {
+ return listOfContaining(generator, asList(firstContainedElement, furtherContainedElements));
+ }
+
+ /**
+ * see {@link #listOfContaining(Function, Object, Object[])}
+ */
+ public final List listOfContaining(Function generator, Collection containedElements) {
+ int maxNumberOfRandomElements = maxNumberOfRandomElements(containedElements);
+
+ List generatedElements = new ArrayList<>();
+ for (T containedValue : containedElements) {
+ generatedElements.addAll(listOf(generator, intNumber(0, maxNumberOfRandomElements)));
+ generatedElements.add(containedValue);
+ }
+ generatedElements.addAll(listOf(generator, intNumber(0, maxNumberOfRandomElements)));
+ return generatedElements;
+ }
+
+ private int maxNumberOfRandomElements(Collection containedElements) {
+ if (containedElements.size() == 0) {
+ return 5;
+ }
+ if (containedElements.size() == 1) {
+ return 2;
+ }
+ return 1;
+ }
+
+ /**
+ * Generates a {@link List} of <T> (by means of {@code generator}). Ensures that the {@link List} contains at least one element.
+ *
+ * Example:
+ *
+ * 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]
+ *
+ *
+ *
+ * @param generator a generator {@link Function} to generate T given a {@link ValueProvider}.
+ *
+ * @return the generated {@link List}.
+ */
+ public List nonEmptyListOf(Function generator) {
+ return listOf(generator, intNumber(1, 5));
+ }
+
+ /**
+ * Generates a {@link List} of <T> (by means of {@code generator}). Might return the empty list.
+ *
+ * Example:
+ *
+ * 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[]
+ *
+ *
+ *
+ * @param generator a generator {@link Function} to generate T given a {@link ValueProvider}.
+ *
+ * @return the generated {@link List}.
+ */
+ public List listOf(Function generator) {
+ return listOf(generator, intNumber(0, 5));
+ }
+
+ /**
+ * Generates a {@link List} of <T> (by means of {@code generator}). Containing exactly {@code numberOfElements} elements.
+ *
+ * Example:
+ *
+ * static class MyBeanTestData {
+ * public static MyBean myBean(ValueProvider valueProvider) {
+ * // builds and returns your bean
+ * }
+ * }
+ *
+ * ValueProvider vp = ValueProviderFactory.createRandomValueProvider();
+ * vp.listOf(MyBeanTestData::myBean, 4); // -> List[myBean_generated_1, myBean_generated_2, myBean_generated_3, myBean_generated_4]
+ *
+ *
+ *
+ * @param generator a generator {@link Function} to generate T given a {@link ValueProvider}.
+ *
+ * @return the generated {@link List}.
+ */
+ public List listOf(Function generator, int numberOfElements) {
+ //noinspection unchecked
+ return IntStream.range(0, numberOfElements)
+ .mapToObj(i -> generator.apply((V) this))
+ .collect(toList());
+ }
+
/**
* Randomly draws true or false.
*
@@ -907,7 +1039,7 @@ private String createIPv6Block() {
}
private List truncateLeadingZerosFromBlocks(List blocks) {
- return blocks.stream().map(this::truncateLeadingZerosFromBlock).collect(Collectors.toList());
+ return blocks.stream().map(this::truncateLeadingZerosFromBlock).collect(toList());
}
private String truncateLeadingZerosFromBlock(String block) {
diff --git a/core/src/test/java/com/tngtech/valueprovider/ValueProviderTest.java b/core/src/test/java/com/tngtech/valueprovider/ValueProviderTest.java
index e45ac7b..c709d17 100644
--- a/core/src/test/java/com/tngtech/valueprovider/ValueProviderTest.java
+++ b/core/src/test/java/com/tngtech/valueprovider/ValueProviderTest.java
@@ -20,6 +20,7 @@
import java.util.stream.LongStream;
import java.util.stream.Stream;
+import lombok.Data;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
@@ -32,6 +33,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;
@@ -42,7 +44,7 @@
import static com.tngtech.valueprovider.ValueProviderTest.TestEnum.SIX;
import static com.tngtech.valueprovider.ValueProviderTest.TestEnum.TEN;
import static com.tngtech.valueprovider.ValueProviderTest.TestEnum.THREE;
-import static com.tngtech.valueprovider.ValueProviderTest.TestEnum.TWELFE;
+import static com.tngtech.valueprovider.ValueProviderTest.TestEnum.TWELVE;
import static com.tngtech.valueprovider.ValueProviderTest.TestEnum.TWO;
import static java.time.LocalDateTime.now;
import static java.util.Arrays.stream;
@@ -218,6 +220,17 @@ void intNumber_should_create_correct_numbers_for_the_limits_of_the_integer_range
assertIntNumber(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
+ private void assertIntNumber(int min, int max) {
+ assertIntNumber(withRandomValues(), min, max);
+ assertIntNumber(withFixedValues(), min, max);
+ }
+
+ private void assertIntNumber(ValueProvider provider, int min, int max) {
+ assertThat(provider.intNumber(min, max))
+ .isGreaterThanOrEqualTo(min)
+ .isLessThanOrEqualTo(max);
+ }
+
@Test
void longNumber_should_create_number_between_min_and_max_and_outside_integer_range() {
for (long i = 0; i < 1000; i++) {
@@ -243,6 +256,18 @@ void longNumber_should_create_correct_numbers_for_the_limits_of_the_long_range()
assertLongNumber(Long.MAX_VALUE, Long.MAX_VALUE);
}
+ private void assertLongNumber(long min, long max) {
+ assertLongNumber(withRandomValues(), min, max);
+ assertLongNumber(withFixedValues(), min, max);
+ }
+
+ private void assertLongNumber(ValueProvider provider, long min, long max) {
+ long longNumber = provider.longNumber(min, max);
+ assertThat(longNumber)
+ .isGreaterThanOrEqualTo(min)
+ .isLessThanOrEqualTo(max);
+ }
+
@Test
void longNumber_should_create_random_numbers_for_the_entire_long_range() {
long min = 0L;
@@ -290,6 +315,16 @@ void bigIntegerNumber_should_create_number_between_min_and_max_and_exceeding_lon
}
}
+ private void assertBigIntegerNumber(BigInteger min, BigInteger max) {
+ assertBigIntegerNumber(withRandomValues(), min, max);
+ assertBigIntegerNumber(withFixedValues(), min, max);
+ }
+
+ private void assertBigIntegerNumber(ValueProvider provider, BigInteger min, BigInteger max) {
+ assertThat(provider.bigIntegerNumber(min, max))
+ .isBetween(min, max);
+ }
+
@SuppressWarnings("unchecked")
@Test
void integer_number_methods_should_handle_range_zero_to_one_properly() {
@@ -386,9 +421,27 @@ void bigDecimalNumber_should_create_number_between_min_and_max() {
}
}
+ private void assertBigDecimalNumber(double min, double max) {
+ assertBigDecimalNumber(withRandomValues(), min, max);
+ assertBigDecimalNumber(withFixedValues(), min, max);
+ }
+
+ private void assertBigDecimalNumber(ValueProvider provider, double min, double max) {
+ assertThat(provider.bigDecimalNumber(min, max))
+ .isBetween(BigDecimal.valueOf(min), BigDecimal.valueOf(max));
+ }
+
@Test
void bigDecimalNumberWithScale_should_return_numbers_within_specified_range_as_long_as_scale_allows_it() {
- assertBigDecimalNumberWithScale2(1.001, 1.004);
+ double min = 1.001;
+ double max = 1.004;
+ int scale = 2;
+ double offsetForScale = 0.01;
+
+ assertThat(withRandomValues().bigDecimalNumberWithScale(min, max, scale))
+ .isBetween(BigDecimal.valueOf(min - offsetForScale), BigDecimal.valueOf(max + offsetForScale));
+ assertThat(withFixedValues().bigDecimalNumberWithScale(min, max, scale))
+ .isBetween(BigDecimal.valueOf(min - offsetForScale), BigDecimal.valueOf(max + offsetForScale));
}
@TestFactory
@@ -396,7 +449,7 @@ List numericString_should_allow_restricting_min_and_max_in_addition
return newArrayList(
lengthMinMax("unrestricted", 3, 100, 200),
lengthMinMax("restricted to range", 3, 120, 180),
- lengthMinMax("restricted to single value", 3, 150, 150)
+ lengthMinMax("restricted to single value", 4, 1234, 1234)
);
}
@@ -404,8 +457,7 @@ private static DynamicTest lengthMinMax(String name, int length, int min, int ma
return DynamicTest.dynamicTest(name, () -> {
String numericString = withRandomValues().numericString(length, min, max);
- assertThat(Integer.valueOf(numericString)).isGreaterThanOrEqualTo(min);
- assertThat(Integer.valueOf(numericString)).isLessThanOrEqualTo(max);
+ assertThat(Integer.valueOf(numericString)).isBetween(min, max);
});
}
@@ -481,7 +533,7 @@ void oneOfExcluding_should_return_allowed_values_only() {
assertThat(random.oneOfExcluding(newArrayList("1", "2", "3", "4"), "3", "4")).isIn("1", "2").isNotIn("3", "4");
assertThat(random.oneOfExcluding(ONE, THREE, FIVE, SEVEN, NINE, ELEVEN))
- .isIn(TWO, FOUR, SIX, EIGHT, TEN, TWELFE)
+ .isIn(TWO, FOUR, SIX, EIGHT, TEN, TWELVE)
.isNotIn(ONE, THREE, FIVE, SEVEN, NINE, ELEVEN);
}
@@ -570,7 +622,59 @@ void someOf_should_return_duplicates_if_input_contains_duplicates() {
assertThat(random.someOf(valueList, valueList.size()))
.isSubsetOf(valueSet)
- .hasSize(valueList.size());
+ .hasSameSizeAs(valueList);
+ }
+
+ @Test
+ void listOf_should_return_provided_number_of_elements() {
+ // given
+ ValueProvider random = withRandomValues();
+ int numberOfElements = random.intNumber(5, 10);
+
+ // when
+ List myBeans = random.listOf(MyBeanTestData::myBean, numberOfElements);
+
+ // then
+ assertThat(myBeans).hasSize(numberOfElements);
+ }
+
+ @Test
+ void listOf_should_return_a_sensible_number_of_elements() {
+ // given
+ ValueProvider random = withRandomValues();
+
+ // when
+ List myBeans = random.listOf(MyBeanTestData::myBean);
+
+ // then
+ assertThat(myBeans).hasSizeLessThanOrEqualTo(5); // 5 is the default
+ }
+
+ @Test
+ void nonEmptyListOf_should_return_at_least_one_element() {
+ // given
+ ValueProvider random = withRandomValues();
+
+ // when
+ List myBeans = random.nonEmptyListOf(MyBeanTestData::myBean);
+
+ // then
+ assertThat(myBeans).isNotEmpty()
+ .hasSizeLessThanOrEqualTo(5); // 5 is the default
+ }
+
+ @Test
+ void listOfContaining_should_return_the_provided_elements_plus_some_randomly_generated_elements() {
+ // given
+ ValueProvider random = withRandomValues();
+
+ // when
+ List myBeans = random.listOfContaining(MyBeanTestData::myBean, myBeanContained(1), myBeanContained(2), myBeanContained(3));
+
+ // then
+ assertThat(myBeans).hasSizeLessThanOrEqualTo(7)
+ // 3 contained beans + max. 1 random 'spacing' bean between each + max. 1 random bean at the beginning/end
+ .contains(myBeanContained(1), myBeanContained(2), myBeanContained(3));
}
@Test
@@ -603,74 +707,28 @@ private static ValueProvider withRandomValues() {
}
private ValueProvider withFixedValues() {
- return withFixedValues(0L);
- }
-
- private ValueProvider withFixedValues(long seed) {
- return new ValueProvider(createReproducibleInitialization(seed));
+ return new ValueProvider(createReproducibleInitialization(0L));
}
enum TestEnum {
- ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELFE
+ ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE
}
enum EmptyTestEnum {
-
- }
-
- private void assertIntNumber(int min, int max) {
- assertIntNumber(withRandomValues(), min, max);
- assertIntNumber(withFixedValues(), min, max);
- }
-
- private void assertIntNumber(ValueProvider provider, int min, int max) {
- assertThat(provider.intNumber(min, max))
- .isGreaterThanOrEqualTo(min)
- .isLessThanOrEqualTo(max);
- }
-
- private void assertLongNumber(long min, long max) {
- assertLongNumber(withRandomValues(), min, max);
- assertLongNumber(withFixedValues(), min, max);
- }
-
- private void assertLongNumber(ValueProvider provider, long min, long max) {
- long longNumber = provider.longNumber(min, max);
- assertThat(longNumber)
- .isGreaterThanOrEqualTo(min)
- .isLessThanOrEqualTo(max);
}
- private void assertBigIntegerNumber(BigInteger min, BigInteger max) {
- assertBigIntegerNumber(withRandomValues(), min, max);
- assertBigIntegerNumber(withFixedValues(), min, max);
- }
-
- private void assertBigIntegerNumber(ValueProvider provider, BigInteger min, BigInteger max) {
- assertThat(provider.bigIntegerNumber(min, max))
- .isGreaterThanOrEqualTo(min)
- .isLessThanOrEqualTo(max);
- }
-
- private void assertBigDecimalNumber(Number min, Number max) {
- assertBigDecimalNumber(withRandomValues(), min, max);
- assertBigDecimalNumber(withFixedValues(), min, max);
- }
-
- private void assertBigDecimalNumber(ValueProvider provider, Number min, Number max) {
- assertThat(provider.bigDecimalNumber(min, max))
- .isGreaterThanOrEqualTo(new BigDecimal(min.doubleValue()))
- .isLessThanOrEqualTo(new BigDecimal(max.doubleValue()));
- }
+ static class MyBeanTestData {
+ public static MyBean myBean(ValueProvider valueProvider) {
+ return new MyBean("randomly generated" + valueProvider.intNumber(0, Integer.MAX_VALUE));
+ }
- private void assertBigDecimalNumberWithScale2(Number min, Number max) {
- assertBigDecimalNumberWithScale2(withRandomValues(), min, max);
- assertBigDecimalNumberWithScale2(withFixedValues(), min, max);
+ public static MyBean myBeanContained(int counter) {
+ return new MyBean("contained" + counter);
+ }
}
- private void assertBigDecimalNumberWithScale2(ValueProvider provider, Number min, Number max) {
- assertThat(provider.bigDecimalNumberWithScale(min, max, 2))
- .isGreaterThanOrEqualTo(new BigDecimal(min.doubleValue() - 0.01))
- .isLessThanOrEqualTo(new BigDecimal(max.doubleValue() + 0.01));
+ @Data
+ static class MyBean {
+ private final String value;
}
}