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


The following commit(s) were added to refs/heads/master by this push:
     new 8f2ae1d  Move check for 2x2 contingency table to the Arguments utility 
class
8f2ae1d is described below

commit 8f2ae1d9a426325905e70c004ce8df17178744a3
Author: aherbert <[email protected]>
AuthorDate: Wed Feb 22 10:18:48 2023 +0000

    Move check for 2x2 contingency table to the Arguments utility class
---
 .../commons/statistics/inference/Arguments.java    | 29 ++++++++++++++++++
 .../statistics/inference/FisherExactTest.java      | 32 ++------------------
 .../statistics/inference/ArgumentsTest.java        | 34 ++++++++++++++++++++++
 3 files changed, 65 insertions(+), 30 deletions(-)

diff --git 
a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/Arguments.java
 
b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/Arguments.java
index ee9e310..715e589 100644
--- 
a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/Arguments.java
+++ 
b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/Arguments.java
@@ -24,6 +24,9 @@ import java.util.EnumSet;
  * @since 1.1
  */
 final class Arguments {
+    /** Two. */
+    private static final int TWO = 2;
+
     /** No instances. */
     private Arguments() {}
 
@@ -225,4 +228,30 @@ final class Arguments {
         }
         return v;
     }
+
+    /**
+     * Check the input is a 2-by-2 contingency table.
+     *
+     * @param table Table.
+     * @throws IllegalArgumentException if the {@code table} is not a 2-by-2 
table; any
+     * table entry is negative; or the sum is zero or is not an integer
+     */
+    static void checkTable(int[][] table) {
+        if (table.length != TWO || table[0].length != TWO || table[1].length 
!= TWO) {
+            throw new InferenceException("Require a 2-by-2 contingency table");
+        }
+        // Must all be positive
+        final int a = table[0][0];
+        final int b = table[0][1];
+        final int c = table[1][0];
+        final int d = table[1][1];
+        // Bitwise OR combines the sign bit from all values
+        Arguments.checkNonNegative(a | b | c | d);
+        // Sum must be an integer
+        final long sum = (long) a + b + c + d;
+        if (sum > Integer.MAX_VALUE) {
+            throw new InferenceException(InferenceException.X_GT_Y, sum, 
Integer.MAX_VALUE);
+        }
+        Arguments.checkStrictlyPositive((int) sum);
+    }
 }
diff --git 
a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/FisherExactTest.java
 
b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/FisherExactTest.java
index 740ee2d..cef4abe 100644
--- 
a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/FisherExactTest.java
+++ 
b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/FisherExactTest.java
@@ -32,8 +32,6 @@ import 
org.apache.commons.statistics.distribution.HypergeometricDistribution;
  * @since 1.1
  */
 public final class FisherExactTest {
-    /** Two. */
-    private static final int TWO = 2;
     /** Default instance. */
     private static final FisherExactTest DEFAULT = new 
FisherExactTest(AlternativeHypothesis.TWO_SIDED);
 
@@ -101,7 +99,7 @@ public final class FisherExactTest {
      * @see #test(int[][])
      */
     public double statistic(int[][] table) {
-        checkTable(table);
+        Arguments.checkTable(table);
         final double a = table[0][0];
         final double b = table[0][1];
         final double c = table[1][0];
@@ -137,7 +135,7 @@ public final class FisherExactTest {
      * @see #statistic(int[][])
      */
     public SignificanceResult test(int[][] table) {
-        checkTable(table);
+        Arguments.checkTable(table);
         final int a = table[0][0];
         final int b = table[0][1];
         final int c = table[1][0];
@@ -214,30 +212,4 @@ public final class FisherExactTest {
         final double pm = distribution.probability(k == m1 ? m2 : m1);
         return pm > pk ? 1 - pm : 1;
     }
-
-    /**
-     * Check the input is a 2-by-2 contingency table.
-     *
-     * @param table Table.
-     * @throws IllegalArgumentException if the {@code table} is not a 2-by-2 
table; any
-     * table entry is negative; or the sum is zero or is not an integer
-     */
-    private static void checkTable(int[][] table) {
-        if (table.length != TWO || table[0].length != TWO || table[1].length 
!= TWO) {
-            throw new InferenceException("Require a 2-by-2 contingency table");
-        }
-        // Must all be positive
-        final int a = table[0][0];
-        final int b = table[0][1];
-        final int c = table[1][0];
-        final int d = table[1][1];
-        // Bitwise OR combines the sign bit from all values
-        Arguments.checkNonNegative(a | b | c | d);
-        // Sum must be an integer
-        final long sum = (long) a + b + c + d;
-        if (sum > Integer.MAX_VALUE) {
-            throw new InferenceException(InferenceException.X_GT_Y, sum, 
Integer.MAX_VALUE);
-        }
-        Arguments.checkStrictlyPositive((int) sum);
-    }
 }
diff --git 
a/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/ArgumentsTest.java
 
b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/ArgumentsTest.java
index c7b68cb..51bf8dd 100644
--- 
a/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/ArgumentsTest.java
+++ 
b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/ArgumentsTest.java
@@ -20,6 +20,7 @@ import java.util.EnumSet;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
 import org.junit.jupiter.params.provider.ValueSource;
 
 /**
@@ -170,4 +171,37 @@ class ArgumentsTest {
         TestUtils.assertThrowsWithMessage(IllegalArgumentException.class,
             () -> Arguments.checkOption(PValueMethod.ESTIMATE, allowed), 
"invalid", "option", PValueMethod.ESTIMATE.toString());
     }
+
+    @Test
+    void testCheckTableInvalid2x2Throws() {
+        Assertions.assertThrows(NullPointerException.class, () -> 
Arguments.checkTable(null));
+        // Non 2-by-2 input
+        Assertions.assertThrows(IllegalArgumentException.class, () -> 
Arguments.checkTable(new int[3][3]));
+        Assertions.assertThrows(IllegalArgumentException.class, () -> 
Arguments.checkTable(new int[2][1]));
+        Assertions.assertThrows(IllegalArgumentException.class, () -> 
Arguments.checkTable(new int[1][2]));
+        // Non-square input
+        final int[][] x = {{1, 2}, {3}};
+        Assertions.assertThrows(IllegalArgumentException.class, () -> 
Arguments.checkTable(x));
+        final int[][] y = {{1}, {2, 3}};
+        Assertions.assertThrows(IllegalArgumentException.class, () -> 
Arguments.checkTable(y));
+    }
+
+    @ParameterizedTest
+    @CsvSource({
+        "0, 0, 0, 0",
+        // Overflow
+        "2147483647, 1, 0, 0",
+        "2147483647, 0, 1, 0",
+        "2147483647, 0, 0, 1",
+        "2147483647, 2147483647, 0, 0",
+        "2147483647, 0, 2147483647, 0",
+        "2147483647, 0, 0, 2147483647",
+        "2147483647, 0, 2147483647, 2147483647",
+        "2147483647, 2147483647, 0, 2147483647",
+        "2147483647, 2147483647, 2147483647, 2147483647",
+    })
+    void testCheckTableInvalidSumThrows(int a, int b, int c, int d) {
+        final int[][] table = {{a, b}, {c, d}};
+        Assertions.assertThrows(IllegalArgumentException.class, () -> 
Arguments.checkTable(table));
+    }
 }

Reply via email to