From 0eb46157e7d5427cd53a7d0c15cf2b88eb43d7e0 Mon Sep 17 00:00:00 2001 From: Michael Kutz Date: Tue, 21 May 2024 14:12:09 +0200 Subject: [PATCH] Add RandomChoiceBuilder --- build.gradle.kts | 29 +++- buildSrc/build.gradle.kts | 5 - .../src/main/kotlin/stubit-style.gradle.kts | 29 ---- .../src/main/kotlin/stubit-testing.gradle.kts | 19 --- manual/build.gradle.kts | 4 +- .../src/docs/asciidoc/chapters/03-random.adoc | 78 ++++++++++ .../java/org/stubit/random/RandomDocTest.java | 77 ++++++++++ modules/http/build.gradle.kts | 13 +- modules/random/build.gradle.kts | 13 +- .../java/org/stubit/random/RandomChoice.java | 11 ++ .../stubit/random/RandomChoiceBuilder.java | 84 +++++++++++ .../org/stubit/random/RandomIntBuilder.java | 63 +++++---- .../random/RandomChoiceBuilderTest.java | 133 ++++++++++++++++++ .../org/stubit/random/RandomChoiceTest.java | 16 ++- .../stubit/random/RandomIntBuilderTest.java | 2 +- pre-commit | 19 +++ pre-push | 19 +++ 17 files changed, 524 insertions(+), 90 deletions(-) delete mode 100644 buildSrc/src/main/kotlin/stubit-style.gradle.kts delete mode 100644 buildSrc/src/main/kotlin/stubit-testing.gradle.kts create mode 100644 manual/src/docs/asciidoc/chapters/03-random.adoc create mode 100644 manual/src/test/java/org/stubit/random/RandomDocTest.java create mode 100644 modules/random/src/main/java/org/stubit/random/RandomChoiceBuilder.java create mode 100644 modules/random/src/test/java/org/stubit/random/RandomChoiceBuilderTest.java create mode 100755 pre-commit create mode 100755 pre-push diff --git a/build.gradle.kts b/build.gradle.kts index 36e37dc..410303a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,8 @@ plugins { base - `stubit-style` id("org.sonarqube") version "5.0.0.4638" id("io.github.gradle-nexus.publish-plugin") version "2.0.0" - id("info.solidsoft.pitest.aggregator") + id("com.diffplug.spotless") version "6.24.0" } repositories { mavenCentral() } @@ -24,3 +23,29 @@ nexusPublishing { } } } + +spotless { + format("misc") { + target("**/*.md", "**/*.xml", "**/*.yml", "**/*.yaml", "**/*.html", "**/*.css", ".gitignore") + targetExclude("**/build/**/*", "**/.idea/**") + trimTrailingWhitespace() + endWithNewline() + indentWithSpaces(2) + } + + java { + target("**/*.java") + targetExclude("**/build/**/*") + googleJavaFormat().reflowLongStrings() + removeUnusedImports() + indentWithSpaces(2) + } + + kotlinGradle { + target("**/*.gradle.kts") + targetExclude("**/build/**/*.gradle.kts") + ktfmt().googleStyle() + } + + freshmark { target("*.md") } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 6fe994f..a92e591 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,8 +1,3 @@ plugins { `kotlin-dsl` } repositories { gradlePluginPortal() } - -dependencies { - implementation("info.solidsoft.gradle.pitest:gradle-pitest-plugin:1.15.0") - implementation("com.diffplug.spotless:spotless-plugin-gradle:6.24.0") -} diff --git a/buildSrc/src/main/kotlin/stubit-style.gradle.kts b/buildSrc/src/main/kotlin/stubit-style.gradle.kts deleted file mode 100644 index bd40950..0000000 --- a/buildSrc/src/main/kotlin/stubit-style.gradle.kts +++ /dev/null @@ -1,29 +0,0 @@ -plugins { id("com.diffplug.spotless") } - -repositories { mavenCentral() } - -spotless { - format("misc") { - target("**/*.md", "**/*.xml", "**/*.yml", "**/*.yaml", "**/*.html", "**/*.css", ".gitignore") - targetExclude("**/build/**/*", "**/.idea/**") - trimTrailingWhitespace() - endWithNewline() - indentWithSpaces(2) - } - - java { - target("**/*.java") - targetExclude("**/build/**/*") - googleJavaFormat().reflowLongStrings() - removeUnusedImports() - indentWithSpaces(2) - } - - kotlinGradle { - target("**/*.gradle.kts") - targetExclude("**/build/**/*.gradle.kts") - ktfmt().googleStyle() - } - - freshmark { target("*.md") } -} diff --git a/buildSrc/src/main/kotlin/stubit-testing.gradle.kts b/buildSrc/src/main/kotlin/stubit-testing.gradle.kts deleted file mode 100644 index 9412754..0000000 --- a/buildSrc/src/main/kotlin/stubit-testing.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - jacoco - id("info.solidsoft.pitest") apply false - java -} - -tasks.withType { - useJUnitPlatform() - systemProperty("junit.jupiter.execution.parallel.enabled", "true") - systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") -} - -tasks.jacocoTestReport { reports { xml.required.set(true) } } - -pitest { - junit5PluginVersion.set("1.0.0") - outputFormats.addAll("XML", "HTML") - timestampedReports.set(false) -} diff --git a/manual/build.gradle.kts b/manual/build.gradle.kts index 35aabe5..fa60a07 100644 --- a/manual/build.gradle.kts +++ b/manual/build.gradle.kts @@ -1,11 +1,13 @@ plugins { id("org.asciidoctor.jvm.convert") version "4.0.2" - `stubit-style` java } +repositories { mavenCentral() } + dependencies { testImplementation(project(":modules:http")) + testImplementation(project(":modules:random")) testImplementation(platform("org.junit:junit-bom:5.10.2")) testImplementation("org.junit.jupiter:junit-jupiter-api") diff --git a/manual/src/docs/asciidoc/chapters/03-random.adoc b/manual/src/docs/asciidoc/chapters/03-random.adoc new file mode 100644 index 0000000..69f53ff --- /dev/null +++ b/manual/src/docs/asciidoc/chapters/03-random.adoc @@ -0,0 +1,78 @@ += Random + +The Random module contains a collection of builders and utility functions to generate random data. + + +== Random Integer + +The link:{javadoc-url}/http/org/stubit/random/RandomIntBuilder.html[`RandomIntBuilder` class] allows to generate random Integer values within a defined min and max range (both inclusive). + +NOTE:: It is not possible to set max to Integer.MAX_VALUE. +The maximum value is Integer.MAX_VALUE - 1. +This is due to the fact that the SecureRandom.nextInt(int) method is exclusive of the upper bound. + + +=== Min and Max + +[source,java,indent=0] +---- +include::../../../test/java/org/stubit/random/RandomDocTest.java[tag=anInt] +---- + + +=== Positive Integer + +[source,java,indent=0] +---- +include::../../../test/java/org/stubit/random/RandomDocTest.java[tag=aPositiveInt] +---- + + +=== Negative Integer + + +[source,java,indent=0] +---- +include::../../../test/java/org/stubit/random/RandomDocTest.java[tag=aNegativeInt] +---- + + +== Random Choice + +The link:{javadoc-url}/http/org/stubit/random/RandomChoiceBuilder.html[`RandomChoiceBuilder` class] allows to make a random choice from the objects in a Collection, an Array, or the values of an Enum type. + + +=== From Collection + +[source,java,indent=0] +---- +include::../../../test/java/org/stubit/random/RandomDocTest.java[tag=from_list] + +include::../../../test/java/org/stubit/random/RandomDocTest.java[tag=from_map] +---- + + +=== From Array + +[source,java,indent=0] +---- +include::../../../test/java/org/stubit/random/RandomDocTest.java[tag=from_ellipsis] + +include::../../../test/java/org/stubit/random/RandomDocTest.java[tag=from_array] +---- + + +=== From Enum Type + +[source,java,indent=0] +---- +include::../../../test/java/org/stubit/random/RandomDocTest.java[tag=from_enum_values] +---- + + +=== Excluding Choices + +[source,java,indent=0] +---- +include::../../../test/java/org/stubit/random/RandomDocTest.java[tag=save] +---- diff --git a/manual/src/test/java/org/stubit/random/RandomDocTest.java b/manual/src/test/java/org/stubit/random/RandomDocTest.java new file mode 100644 index 0000000..5e44cff --- /dev/null +++ b/manual/src/test/java/org/stubit/random/RandomDocTest.java @@ -0,0 +1,77 @@ +package org.stubit.random; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.stubit.random.RandomChoiceBuilder.from; +import static org.stubit.random.RandomChoiceBuilder.fromValuesOf; +import static org.stubit.random.RandomIntBuilder.*; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class RandomDocTest { + + @Test + void randomInt_examples() { + // tag::anInt[] + int someInt = anInt().build(); + assertThat(someInt).isBetween(Integer.MIN_VALUE, Integer.MAX_VALUE - 1); + + int someIntBetween42And4711 = anInt().min(42).max(4711).build(); + assertThat(someIntBetween42And4711).isBetween(42, 4711); + + int someIntLessThan4711 = anInt().max(4711).build(); + assertThat(someIntLessThan4711).isLessThanOrEqualTo(4711); + + int someIntGreaterThanMinus10 = anInt().min(-42).build(); + assertThat(someIntGreaterThanMinus10).isGreaterThanOrEqualTo(-42); + // end::anInt[] + + // tag::aPositiveInt[] + int somePositiveInt = aPositiveInt().build(); + assertThat(somePositiveInt).isPositive().isNotZero().isLessThan(Integer.MAX_VALUE); + // end::aPositiveInt[] + + // tag::aNegativeInt[] + int someNegativeInt = aNegativeInt().build(); + assertThat(someNegativeInt).isNegative().isNotZero().isGreaterThanOrEqualTo(Integer.MIN_VALUE); + // end::aNegativeInt[] + } + + @Test + void anyOf_examples() { + // tag::from_ellipsis[] + assertThat(from("a", "b", "c").chooseAny()).isIn("a", "b", "c"); + // end::from_ellipsis[] + + // tag::from_array[] + String[] choiceArray = {"a", "b", "c"}; + assertThat(from(choiceArray).chooseAny()).isIn((Object[]) choiceArray); + // end::from_array[] + + // tag::from_list[] + var choicesList = List.of("a", "b", "c"); + assertThat(from(choicesList).chooseAny()).isIn(choicesList); + // end::from_list[] + + // tag::from_map[] + var choicesMap = Map.of("a", 1, "b", 2, "c", 3); + assertThat(from(choicesMap).chooseAny()).isIn(choicesMap); + // end::from_map[] + + // tag::from_enum_values[] + enum Color { + RED, + GREEN, + BLUE + } + assertThat(fromValuesOf(Color.class).chooseAny()).isIn(Color.RED, Color.GREEN, Color.BLUE); + // end::from_enum_values[] + + // tag::save[] + var allChoices = List.of("a", "b", "c"); + var excludedChoice = "a"; + assertThat(from(allChoices).save(excludedChoice).chooseAny()).isNotEqualTo(excludedChoice); + // end::save[] + } +} diff --git a/modules/http/build.gradle.kts b/modules/http/build.gradle.kts index c1ba987..0e668f1 100644 --- a/modules/http/build.gradle.kts +++ b/modules/http/build.gradle.kts @@ -1,8 +1,7 @@ plugins { `stubit-module` `stubit-publish` - `stubit-style` - `stubit-testing` + id("info.solidsoft.pitest") version "1.15.0" } repositories { mavenCentral() } @@ -11,7 +10,15 @@ dependencies { testImplementation(platform("org.junit:junit-bom:5.10.2")) testImplementation("org.junit.jupiter:junit-jupiter-api") testImplementation("org.junit.jupiter:junit-jupiter-params") + testImplementation("org.assertj:assertj-core:3.25.3") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +} - testImplementation("org.assertj:assertj-core:3.25.3") +tasks.withType { useJUnitPlatform() } + +pitest { + junit5PluginVersion.set("1.0.0") + outputFormats.addAll("XML", "HTML") + timestampedReports.set(false) } diff --git a/modules/random/build.gradle.kts b/modules/random/build.gradle.kts index c1ba987..0e668f1 100644 --- a/modules/random/build.gradle.kts +++ b/modules/random/build.gradle.kts @@ -1,8 +1,7 @@ plugins { `stubit-module` `stubit-publish` - `stubit-style` - `stubit-testing` + id("info.solidsoft.pitest") version "1.15.0" } repositories { mavenCentral() } @@ -11,7 +10,15 @@ dependencies { testImplementation(platform("org.junit:junit-bom:5.10.2")) testImplementation("org.junit.jupiter:junit-jupiter-api") testImplementation("org.junit.jupiter:junit-jupiter-params") + testImplementation("org.assertj:assertj-core:3.25.3") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +} - testImplementation("org.assertj:assertj-core:3.25.3") +tasks.withType { useJUnitPlatform() } + +pitest { + junit5PluginVersion.set("1.0.0") + outputFormats.addAll("XML", "HTML") + timestampedReports.set(false) } diff --git a/modules/random/src/main/java/org/stubit/random/RandomChoice.java b/modules/random/src/main/java/org/stubit/random/RandomChoice.java index 6141a66..9c1a25e 100644 --- a/modules/random/src/main/java/org/stubit/random/RandomChoice.java +++ b/modules/random/src/main/java/org/stubit/random/RandomChoice.java @@ -57,4 +57,15 @@ public static T anyOf(Collection choices) { public static Entry anyOf(Map choices) { return anyOf(choices.entrySet()); } + + /** + * Randomly selects an element from the values of the provided choices {@link Enum} class. + * + * @param enumType the {@link Enum} type + * @return a randomly selected {@link Enum} constant from the provided choices enumType + * @param the type of the choices + */ + public static > T random(Class enumType) { + return anyOf(enumType.getEnumConstants()); + } } diff --git a/modules/random/src/main/java/org/stubit/random/RandomChoiceBuilder.java b/modules/random/src/main/java/org/stubit/random/RandomChoiceBuilder.java new file mode 100644 index 0000000..18ef149 --- /dev/null +++ b/modules/random/src/main/java/org/stubit/random/RandomChoiceBuilder.java @@ -0,0 +1,84 @@ +package org.stubit.random; + +import java.security.SecureRandom; +import java.util.*; + +/** Randomly selects an element from a collection of choices. */ +public class RandomChoiceBuilder { + + private static final SecureRandom random = new SecureRandom(); + + private final List choices; + + private RandomChoiceBuilder(Collection choices) { + if (choices.isEmpty()) { + throw new IllegalArgumentException("No choices provided"); + } + this.choices = new ArrayList<>(choices); + } + + /** + * @param choices a {@link Collection} of choices + * @return a new {@link RandomChoiceBuilder} with the provided choices + * @param the type of the choices + */ + public static RandomChoiceBuilder from(Collection choices) { + return new RandomChoiceBuilder<>(choices); + } + + /** + * @param enumType the {@link Enum} type + * @return a new {@link RandomChoiceBuilder} with the provided enumType's values as choices + * @param the type of the choices + */ + public static > RandomChoiceBuilder fromValuesOf( + Class enumType) { + return from(Arrays.asList(enumType.getEnumConstants())); + } + + /** + * @param choices an array of choices + * @return a new {@link RandomChoiceBuilder} with the provided choices + * @param the type of the choices + */ + @SafeVarargs + public static RandomChoiceBuilder from(T... choices) { + return from(Arrays.asList(choices)); + } + + /** + * Excludes the provided choices from the selection + * + * @param excluded the excluded choices + * @return this + * @throws IllegalArgumentException if no choices remain + */ + @SafeVarargs + public final RandomChoiceBuilder save(T... excluded) { + return save(Arrays.asList(excluded)); + } + + /** + * Excludes the provided choices from the selection + * + * @param excluded the excluded choices + * @return this + * @throws IllegalArgumentException if no choices remain + */ + public RandomChoiceBuilder save(Collection excluded) { + this.choices.removeAll(excluded); + if (choices.isEmpty()) { + throw new IllegalArgumentException("No choices left"); + } + return this; + } + + /** + * Returns and removes a randomly selected element from the {@link #choices}. + * + * @return a randomly selected element form the {@link #choices} + */ + public T chooseAny() { + return choices.get(random.nextInt(choices.size())); + } +} diff --git a/modules/random/src/main/java/org/stubit/random/RandomIntBuilder.java b/modules/random/src/main/java/org/stubit/random/RandomIntBuilder.java index 5609c25..bb998e5 100644 --- a/modules/random/src/main/java/org/stubit/random/RandomIntBuilder.java +++ b/modules/random/src/main/java/org/stubit/random/RandomIntBuilder.java @@ -6,63 +6,76 @@ public class RandomIntBuilder { private final SecureRandom secureRandom = new SecureRandom(); - private int min; - private int max; + private int minInclusive; + private int maxInclusive; private RandomIntBuilder(int min, int max) { - this.min = min; - this.max = max; + this.minInclusive = min; + this.maxInclusive = max; } /** - * @return a random integer between 1 and {@link Integer#MAX_VALUE} + * @return a {@link RandomIntBuilder} with min {@link Integer#MIN_VALUE} and max {@link + * Integer#MAX_VALUE} - 1. */ - public static RandomIntBuilder aPositiveInt() { - return new RandomIntBuilder(1, Integer.MAX_VALUE); + public static RandomIntBuilder anInt() { + return new RandomIntBuilder(Integer.MIN_VALUE, Integer.MAX_VALUE - 1); } /** - * @return a random integer between {@link Integer#MIN_VALUE} and -1 + * @return a {@link RandomIntBuilder} with min 1 and max {@link Integer#MAX_VALUE} - 1. */ - public static RandomIntBuilder aNegativeInt() { - return new RandomIntBuilder(Integer.MIN_VALUE, -1); + public static RandomIntBuilder aPositiveInt() { + return anInt().min(1); } /** - * @return a random integer between {@link Integer#MIN_VALUE} and {@link Integer#MAX_VALUE} + * @return a {@link RandomIntBuilder} with min {@link Integer#MIN_VALUE} and max -1 */ - public static RandomIntBuilder anInt() { - return new RandomIntBuilder(Integer.MIN_VALUE, Integer.MAX_VALUE); + public static RandomIntBuilder aNegativeInt() { + return anInt().max(-1); } /** - * @param min the minimum value (inclusive) + * @param minInclusive the minimum value (inclusive) * @return this + * @throws IllegalArgumentException if {@code minInclusive} is greater than or equal to {@link + * #maxInclusive} */ - public RandomIntBuilder min(int min) { - this.min = min; - if (max <= min) { - max = min + 1; + public RandomIntBuilder min(int minInclusive) { + this.minInclusive = minInclusive; + if (minInclusive > maxInclusive) { + throw new IllegalArgumentException( + "Can't set min to %d, as it must not be greater than max (%d)" + .formatted(minInclusive, maxInclusive)); } return this; } /** - * @param max the maximum value (exclusive) + * @param maxInclusive the maximum value (exclusive) * @return this + * @throws IllegalArgumentException if {@code maxInclusive} is less than or equal to {@link + * #minInclusive} or if {@code maxInclusive} is equal to {@link Integer#MAX_VALUE} */ - public RandomIntBuilder max(int max) { - this.max = max; - if (min >= max) { - min = max - 1; + public RandomIntBuilder max(int maxInclusive) { + if (maxInclusive < minInclusive) { + throw new IllegalArgumentException( + "Can't set max to %d, as it must not less than min (%d)" + .formatted(maxInclusive, minInclusive)); + } + if (maxInclusive == Integer.MAX_VALUE) { + throw new IllegalArgumentException( + "Can't set max to %d (Integer.MAX_VALUE)".formatted(maxInclusive)); } + this.maxInclusive = maxInclusive; return this; } /** - * @return a random integer between {@link #min} (inclusive) and {@link #max} (exclusive) + * @return a random integer between {@link #minInclusive} and {@link #maxInclusive} */ public int build() { - return secureRandom.nextInt(min, max); + return secureRandom.nextInt(minInclusive, maxInclusive + 1); } } diff --git a/modules/random/src/test/java/org/stubit/random/RandomChoiceBuilderTest.java b/modules/random/src/test/java/org/stubit/random/RandomChoiceBuilderTest.java new file mode 100644 index 0000000..ec87837 --- /dev/null +++ b/modules/random/src/test/java/org/stubit/random/RandomChoiceBuilderTest.java @@ -0,0 +1,133 @@ +package org.stubit.random; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.stubit.random.RandomChoiceBuilder.from; +import static org.stubit.random.RandomChoiceBuilder.fromValuesOf; + +import java.util.Collection; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RandomChoiceBuilderTest { + + @Test + void from_ellipsis() { + assertThat(from("a", "b", "c").chooseAny()).isIn("a", "b", "c"); + } + + @Test + void from_ellipsis_single() { + assertThat(from("a").chooseAny()).isEqualTo("a"); + } + + @Test + void from_ellipsis_empty() { + assertThatIllegalArgumentException() + .isThrownBy(RandomChoiceBuilder::from) + .withMessage("No choices provided"); + } + + @Test + void from_array() { + String[] choicesArray = {"a", "b", "c"}; + assertThat(from(choicesArray).chooseAny()).isIn((Object[]) choicesArray); + } + + @Test + void from_array_single() { + String singleChoice = "a"; + String[] choicesArray = {singleChoice}; + assertThat(from(choicesArray).chooseAny()).isEqualTo(singleChoice); + } + + @Test + void from_array_empty() { + String[] emptyChoicesArray = {}; + assertThatIllegalArgumentException() + .isThrownBy(() -> from(emptyChoicesArray)) + .withMessage("No choices provided"); + } + + @Test + void from_collection() { + Collection choicesList = List.of("a", "b", "c"); + assertThat(from(choicesList).chooseAny()).isIn(choicesList); + } + + @Test + void from_collection_single() { + String singleChoice = "a"; + Collection choicesCollection = List.of(singleChoice); + assertThat(from(choicesCollection).chooseAny()).isEqualTo(singleChoice); + } + + @Test + void from_collection_Empty() { + Collection emptyChoicesCollection = List.of(); + assertThatIllegalArgumentException() + .isThrownBy(() -> from(emptyChoicesCollection)) + .withMessage("No choices provided"); + } + + @Test + void from_enum() { + enum ChoiceEnum { + A, + B, + C + } + assertThat(fromValuesOf(ChoiceEnum.class).chooseAny()).isIn((Object[]) ChoiceEnum.values()); + } + + @Test + void from_enum_single() { + enum SingleChoiceEnum { + SINGLE_CHOICE + } + assertThat(fromValuesOf(SingleChoiceEnum.class).chooseAny()) + .isEqualTo(SingleChoiceEnum.SINGLE_CHOICE); + } + + @Test + void from_enum_empty() { + enum EmptyChoiceEnum {} + assertThatIllegalArgumentException() + .isThrownBy(() -> fromValuesOf(EmptyChoiceEnum.class)) + .withMessage("No choices provided"); + } + + @Test + void save_one() { + String excludedChoice = "a"; + Collection remainingChoices = List.of("b", "c"); + Collection allChoices = List.of(excludedChoice, "b", "c"); + assertThat(from(allChoices).save(excludedChoice).chooseAny()) + .isNotEqualTo(excludedChoice) + .isIn(remainingChoices); + } + + @Test + void save_all_but_one() { + String remainingChoice = "c"; + Collection excludedChoices = List.of("a", "b"); + Collection allChoices = List.of("a", "b", remainingChoice); + assertThat(from(allChoices).save(excludedChoices).chooseAny()).isEqualTo(remainingChoice); + } + + @Test + void save_all() { + Collection allChoices = List.of("a", "b", "c"); + assertThatIllegalArgumentException() + .isThrownBy(() -> from(allChoices).save(allChoices)) + .withMessage("No choices left"); + } + + @Test + void save_unknown() { + Collection excludedChoices = List.of("c", "x"); + Collection remainingChoices = List.of("a", "b"); + Collection allChoices = List.of("a", "b", "c"); + assertThat(from(allChoices).save(excludedChoices).chooseAny()).isIn(remainingChoices); + } +} diff --git a/modules/random/src/test/java/org/stubit/random/RandomChoiceTest.java b/modules/random/src/test/java/org/stubit/random/RandomChoiceTest.java index eb11681..d9a778d 100644 --- a/modules/random/src/test/java/org/stubit/random/RandomChoiceTest.java +++ b/modules/random/src/test/java/org/stubit/random/RandomChoiceTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.stubit.random.RandomChoice.anyOf; +import static org.stubit.random.RandomChoice.random; import java.util.List; import java.util.Map; @@ -13,7 +14,7 @@ class RandomChoiceTest { @Test void anyOf_ellipsis() { String[] choices = {"a", "b", "c"}; - assertThat(anyOf(choices)).isIn(choices); + assertThat(anyOf(choices)).isIn((Object[]) choices); } @Test @@ -32,7 +33,7 @@ void anyOf_ellipsis_empty() { @Test void anyOf_collection() { var choices = List.of("a", "b", "c"); - assertThat(anyOf(choices)).isIn("a", "b", "c"); + assertThat(anyOf(choices)).isIn(choices); } @Test @@ -66,4 +67,15 @@ void anyOf_map_empty() { .isThrownBy(() -> anyOf(Map.of())) .withMessage("No choices provided"); } + + @Test + void random_enum() { + enum ChoiceEnum { + A, + B, + C + } + + assertThat(random(ChoiceEnum.class)).isIn((Object[]) ChoiceEnum.values()); + } } diff --git a/modules/random/src/test/java/org/stubit/random/RandomIntBuilderTest.java b/modules/random/src/test/java/org/stubit/random/RandomIntBuilderTest.java index 9b88b5b..563ad12 100644 --- a/modules/random/src/test/java/org/stubit/random/RandomIntBuilderTest.java +++ b/modules/random/src/test/java/org/stubit/random/RandomIntBuilderTest.java @@ -50,7 +50,7 @@ void max() { @Test void max_MIN_VALUE() { - int max = MIN_VALUE + 1; + int max = MIN_VALUE; int result = anInt().max(max).build(); assertThat(result).isEqualTo(MIN_VALUE); } diff --git a/pre-commit b/pre-commit new file mode 100755 index 0000000..7a3c659 --- /dev/null +++ b/pre-commit @@ -0,0 +1,19 @@ +#!/bin/sh + +stagedFiles=$(git diff --staged --name-only) + +echo "🧹 Formatting code running spotlessApply…" +./gradlew spotlessApply +if [ $? -ne 0 ]; then + echo '… ✗ formatting failed' + exit 1 +fi + +for file in $stagedFiles; do + if test -f "$file"; then + git add "$file" + fi +done + +echo "… ✓" +exit 0 diff --git a/pre-push b/pre-push new file mode 100755 index 0000000..93a81d4 --- /dev/null +++ b/pre-push @@ -0,0 +1,19 @@ +#!/bin/bash + +current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') +protected_branches=( master main ) + +for i in "${protected_branches[@]}"; do + if [[ $i == $current_branch ]]; then + echo '⚠️ Attention! You are pushing to a protected branch. Running checks…' + + ./gradlew check + if [ $? -ne 0 ]; then + echo '… ✗ check failed' + exit 1 + fi + fi +done + +echo "… ✓" +exit 0