JAL-98 throw exception (unhandled) for int overthrow while counting
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 3 Oct 2016 13:21:26 +0000 (14:21 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 3 Oct 2016 13:21:26 +0000 (14:21 +0100)
src/jalview/ext/android/SparseIntArray.java
test/jalview/ext/android/SparseIntArrayTest.java

index e286cb4..2b9c4af 100644 (file)
@@ -355,6 +355,8 @@ public class SparseIntArray implements Cloneable
    * @param key
    * @oparam toAdd
    * @return the new value of the count for the key
+   * @throw ArithmeticException if the result would exceed the maximum value of
+   *        an int
    */
   public int add(int key, int toAdd)
   {
@@ -362,6 +364,7 @@ public class SparseIntArray implements Cloneable
     int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
     if (i >= 0)
     {
+      checkOverflow(mValues[i], toAdd);
       mValues[i] += toAdd;
       newValue = mValues[i];
     }
@@ -389,4 +392,34 @@ public class SparseIntArray implements Cloneable
     }
     return newValue;
   }
+
+  /**
+   * Throws ArithmeticException if adding addend to value would exceed the range
+   * of int
+   * 
+   * @param value
+   * @param addend
+   */
+  static void checkOverflow(int value, int addend)
+  {
+    /*
+     * test cases being careful to avoid overflow while testing!
+     */
+    if (addend > 0)
+    {
+      if (value > 0 && Integer.MAX_VALUE - value < addend)
+      {
+        throw new ArithmeticException("Integer overflow adding " + addend
+                + " to  " + value);
+      }
+    }
+    else if (addend < 0)
+    {
+      if (value < 0 && Integer.MIN_VALUE - value > addend)
+      {
+        throw new ArithmeticException("Integer underflow adding " + addend
+                + " to  " + value);
+      }
+    }
+  }
 }
index 3919e33..0ce0467 100644 (file)
@@ -1,6 +1,7 @@
 package jalview.ext.android;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
 
 import org.testng.annotations.Test;
 
@@ -35,9 +36,89 @@ public class SparseIntArrayTest
     assertEquals(counter.add('Q', 4), 11);
 
     counter.put('x', Integer.MAX_VALUE);
-    counter.add('x', 1);
+    try
+    {
+      counter.add('x', 1);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
   
     counter.put('y', Integer.MIN_VALUE);
-    counter.add('y', -1);
+    try
+    {
+      counter.add('y', -1);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
   }
+
+  @Test(groups = "Functional")
+  public void testCheckOverflow()
+  {
+    // things that don't overflow:
+    SparseIntArray.checkOverflow(Integer.MAX_VALUE, 0);
+    SparseIntArray.checkOverflow(Integer.MAX_VALUE, -1);
+    SparseIntArray.checkOverflow(Integer.MAX_VALUE, Integer.MIN_VALUE);
+    SparseIntArray.checkOverflow(Integer.MAX_VALUE, -Integer.MAX_VALUE);
+    SparseIntArray.checkOverflow(0, -Integer.MAX_VALUE);
+    SparseIntArray.checkOverflow(0, Integer.MIN_VALUE);
+    SparseIntArray.checkOverflow(Integer.MIN_VALUE, 0);
+    SparseIntArray.checkOverflow(Integer.MIN_VALUE, 1);
+    SparseIntArray.checkOverflow(Integer.MIN_VALUE, Integer.MAX_VALUE);
+
+    // and some that do
+    try
+    {
+      SparseIntArray.checkOverflow(Integer.MAX_VALUE, 1);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(Integer.MAX_VALUE - 1, 2);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(1, Integer.MAX_VALUE);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(Integer.MIN_VALUE, -1);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(Integer.MIN_VALUE + 1, -2);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(-1, Integer.MIN_VALUE);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+  }
+
 }