This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-statistics.git

commit 66c68c802ade16523298d91882a6eb9e6c925a5f
Author: Alex Herbert <aherb...@apache.org>
AuthorDate: Thu Feb 22 08:19:46 2024 +0000

    Throw NPE if user-supplied arguments are null
---
 .../commons/statistics/ranking/NaturalRanking.java | 30 ++++++++++++++----
 .../statistics/ranking/NaturalRankingTest.java     | 36 +++++++++++++++++-----
 2 files changed, 53 insertions(+), 13 deletions(-)

diff --git 
a/commons-statistics-ranking/src/main/java/org/apache/commons/statistics/ranking/NaturalRanking.java
 
b/commons-statistics-ranking/src/main/java/org/apache/commons/statistics/ranking/NaturalRanking.java
index 1445592..5bb81ac 100644
--- 
a/commons-statistics-ranking/src/main/java/org/apache/commons/statistics/ranking/NaturalRanking.java
+++ 
b/commons-statistics-ranking/src/main/java/org/apache/commons/statistics/ranking/NaturalRanking.java
@@ -17,6 +17,7 @@
 package org.apache.commons.statistics.ranking;
 
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.SplittableRandom;
 import java.util.function.DoubleUnaryOperator;
 import java.util.function.IntUnaryOperator;
@@ -31,7 +32,7 @@ import java.util.function.IntUnaryOperator;
  * {@link TiesStrategy#AVERAGE}, respectively.
  *
  * <p>When using {@link TiesStrategy#RANDOM}, a generator of random values in 
{@code [0, x)}
- * supplied as a {@link IntUnaryOperator} argument; otherwise a default is 
created
+ * can be supplied as a {@link IntUnaryOperator} argument; otherwise a default 
is created
  * on-demand. The source of randomness can be supplied using a method 
reference.
  * The following example creates a ranking with NaN values with the highest
  * ranking and ties resolved randomly:
@@ -83,6 +84,12 @@ import java.util.function.IntUnaryOperator;
  * @since 1.1
  */
 public class NaturalRanking implements RankingAlgorithm {
+    /** Message for a null user-supplied {@link NaNStrategy}. */
+    private static final String NULL_NAN_STRATEGY = "nanStrategy";
+    /** Message for a null user-supplied {@link TiesStrategy}. */
+    private static final String NULL_TIES_STRATEGY = "tiesStrategy";
+    /** Message for a null user-supplied source of randomness. */
+    private static final String NULL_RANDOM_SOURCE = "randomIntFunction";
     /** Default NaN strategy. */
     private static final NaNStrategy DEFAULT_NAN_STRATEGY = NaNStrategy.FAILED;
     /** Default ties strategy. */
@@ -121,9 +128,11 @@ public class NaturalRanking implements RankingAlgorithm {
      * source of randomness is used to resolve ties.
      *
      * @param tiesStrategy TiesStrategy to use.
+     * @throws NullPointerException if the strategy is {@code null}
      */
     public NaturalRanking(TiesStrategy tiesStrategy) {
-        this(DEFAULT_NAN_STRATEGY, tiesStrategy, null);
+        this(DEFAULT_NAN_STRATEGY,
+            Objects.requireNonNull(tiesStrategy, NULL_TIES_STRATEGY), null);
     }
 
     /**
@@ -131,9 +140,11 @@ public class NaturalRanking implements RankingAlgorithm {
      * {@link TiesStrategy#AVERAGE}.
      *
      * @param nanStrategy NaNStrategy to use.
+     * @throws NullPointerException if the strategy is {@code null}
      */
     public NaturalRanking(NaNStrategy nanStrategy) {
-        this(nanStrategy, DEFAULT_TIES_STRATEGY, null);
+        this(Objects.requireNonNull(nanStrategy, NULL_NAN_STRATEGY),
+            DEFAULT_TIES_STRATEGY, null);
     }
 
     /**
@@ -145,10 +156,12 @@ public class NaturalRanking implements RankingAlgorithm {
      *
      * @param nanStrategy NaNStrategy to use.
      * @param tiesStrategy TiesStrategy to use.
+     * @throws NullPointerException if any strategy is {@code null}
      */
     public NaturalRanking(NaNStrategy nanStrategy,
                           TiesStrategy tiesStrategy) {
-        this(nanStrategy, tiesStrategy, null);
+        this(Objects.requireNonNull(nanStrategy, NULL_NAN_STRATEGY),
+            Objects.requireNonNull(tiesStrategy, NULL_TIES_STRATEGY), null);
     }
 
     /**
@@ -157,9 +170,11 @@ public class NaturalRanking implements RankingAlgorithm {
      *
      * @param randomIntFunction Source of random index data.
      * Function maps positive {@code x} randomly to {@code [0, x)}
+     * @throws NullPointerException if the source of randomness is {@code null}
      */
     public NaturalRanking(IntUnaryOperator randomIntFunction) {
-        this(DEFAULT_NAN_STRATEGY, TiesStrategy.RANDOM, randomIntFunction);
+        this(DEFAULT_NAN_STRATEGY, TiesStrategy.RANDOM,
+            Objects.requireNonNull(randomIntFunction, NULL_RANDOM_SOURCE));
     }
 
     /**
@@ -169,10 +184,12 @@ public class NaturalRanking implements RankingAlgorithm {
      * @param nanStrategy NaNStrategy to use.
      * @param randomIntFunction Source of random index data.
      * Function maps positive {@code x} randomly to {@code [0, x)}
+     * @throws NullPointerException if the strategy or source of randomness 
are {@code null}
      */
     public NaturalRanking(NaNStrategy nanStrategy,
                           IntUnaryOperator randomIntFunction) {
-        this(nanStrategy, TiesStrategy.RANDOM, randomIntFunction);
+        this(Objects.requireNonNull(nanStrategy, NULL_NAN_STRATEGY), 
TiesStrategy.RANDOM,
+            Objects.requireNonNull(randomIntFunction, NULL_RANDOM_SOURCE));
     }
 
     /**
@@ -183,6 +200,7 @@ public class NaturalRanking implements RankingAlgorithm {
     private NaturalRanking(NaNStrategy nanStrategy,
                            TiesStrategy tiesStrategy,
                            IntUnaryOperator randomIntFunction) {
+        // User-supplied arguments are checked for non-null in the respective 
constructor
         this.nanStrategy = nanStrategy;
         this.tiesStrategy = tiesStrategy;
         this.randomIntFunction = randomIntFunction;
diff --git 
a/commons-statistics-ranking/src/test/java/org/apache/commons/statistics/ranking/NaturalRankingTest.java
 
b/commons-statistics-ranking/src/test/java/org/apache/commons/statistics/ranking/NaturalRankingTest.java
index d292a01..7d8c5e3 100644
--- 
a/commons-statistics-ranking/src/test/java/org/apache/commons/statistics/ranking/NaturalRankingTest.java
+++ 
b/commons-statistics-ranking/src/test/java/org/apache/commons/statistics/ranking/NaturalRankingTest.java
@@ -19,6 +19,7 @@ package org.apache.commons.statistics.ranking;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.function.IntUnaryOperator;
 import java.util.stream.Collectors;
 import java.util.stream.DoubleStream;
@@ -30,6 +31,7 @@ import org.apache.commons.rng.sampling.PermutationSampler;
 import org.apache.commons.rng.simple.RandomSource;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.function.Executable;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.CsvSource;
@@ -56,7 +58,7 @@ class NaturalRankingTest {
     void testProperties() {
         final TiesStrategy defaultTs = TiesStrategy.AVERAGE;
         final NaNStrategy defaultNs = NaNStrategy.FAILED;
-        final IntUnaryOperator randomSource = null;
+        final IntUnaryOperator randomSource = x -> x;
         NaturalRanking ranking;
 
         ranking = new NaturalRanking();
@@ -89,12 +91,32 @@ class NaturalRankingTest {
     }
 
     @Test
-    void testNullStrategy() {
-        final double[] data = new double[5];
-        final NaturalRanking r1 = new NaturalRanking((NaNStrategy)null);
-        Assertions.assertThrows(NullPointerException.class, () -> 
r1.apply(data));
-        final NaturalRanking r2 = new NaturalRanking((TiesStrategy)null);
-        Assertions.assertThrows(NullPointerException.class, () -> 
r2.apply(data));
+    void testNullArguments() {
+        final TiesStrategy nullTiesStrategy = null;
+        final TiesStrategy tiesStrategy = TiesStrategy.AVERAGE;
+        final NaNStrategy nullNaNStrategy = null;
+        final NaNStrategy nanStrategy = NaNStrategy.FIXED;
+        final IntUnaryOperator nullRandomness = null;
+        final IntUnaryOperator randomness = x -> x;
+        assertThrowsNPEWithKeywords(() -> new 
NaturalRanking(nullTiesStrategy), "ties", "strategy");
+        assertThrowsNPEWithKeywords(() -> new NaturalRanking(nullNaNStrategy), 
"nan", "strategy");
+        assertThrowsNPEWithKeywords(
+            () -> new NaturalRanking(nullNaNStrategy, tiesStrategy), "nan", 
"strategy");
+        assertThrowsNPEWithKeywords(
+            () -> new NaturalRanking(nanStrategy, nullTiesStrategy), "ties", 
"strategy");
+        assertThrowsNPEWithKeywords(() -> new NaturalRanking(nullRandomness), 
"random");
+        assertThrowsNPEWithKeywords(
+            () -> new NaturalRanking(nullNaNStrategy, randomness), "nan", 
"strategy");
+        assertThrowsNPEWithKeywords(
+            () -> new NaturalRanking(nanStrategy, nullRandomness), "random");
+    }
+
+    private static void assertThrowsNPEWithKeywords(Executable executable, 
String... keywords) {
+        final NullPointerException e = 
Assertions.assertThrows(NullPointerException.class, executable);
+        final String msg = e.getMessage().toLowerCase(Locale.ROOT);
+        for (final String s : keywords) {
+            Assertions.assertTrue(msg.contains(s), () -> "Missing keyword: " + 
s);
+        }
     }
 
     /**

Reply via email to