Support explicit + in Byte, Short, Integer, Long.

Bug: 5239391
Change-Id: I2b25228815d70d570d537db0ed9b5b759f25b5a3
diff --git a/luni/src/main/java/java/lang/Integer.java b/luni/src/main/java/java/lang/Integer.java
index 5a70c6c..8ae0312 100644
--- a/luni/src/main/java/java/lang/Integer.java
+++ b/luni/src/main/java/java/lang/Integer.java
@@ -126,7 +126,8 @@
 
     /**
      * Compares two {@code int} values.
-     * @return 0 if lhs = rhs, less than 0 if lhs < rhs, and greater than 0 if lhs > rhs.
+     * @return 0 if lhs = rhs, less than 0 if lhs < rhs, and greater than 0
+     *         if lhs > rhs.
      * @since 1.7
      */
     public static int compare(int lhs, int rhs) {
@@ -140,24 +141,26 @@
     /**
      * Parses the specified string and returns a {@code Integer} instance if the
      * string can be decoded into an integer value. The string may be an
-     * optional minus sign "-" followed by a hexadecimal ("0x..." or "#..."),
-     * octal ("0..."), or decimal ("...") representation of an integer.
+     * optional sign character ("-" or "+") followed by a hexadecimal ("0x..."
+     * or "#..."), octal ("0..."), or decimal ("...") representation of an
+     * integer.
      *
      * @param string
      *            a string representation of an integer value.
      * @return an {@code Integer} containing the value represented by
      *         {@code string}.
      * @throws NumberFormatException
-     *             if {@code string} cannot be parsed as an integer value.
+     *            if {@code string} cannot be parsed as an integer value.
      */
     public static Integer decode(String string) throws NumberFormatException {
-        int length = string.length(), i = 0;
+        int length = string.length();
         if (length == 0) {
             throw invalidInt(string);
         }
+        int i = 0;
         char firstDigit = string.charAt(i);
         boolean negative = firstDigit == '-';
-        if (negative) {
+        if (negative || firstDigit == '+') {
             if (length == 1) {
                 throw invalidInt(string);
             }
@@ -319,8 +322,8 @@
 
     /**
      * Parses the specified string as a signed decimal integer value. The ASCII
-     * character \u002d ('-') is recognized as the minus sign.
-     *
+     * characters \u002d ('-') and \u002b ('+') are recognized as the minus and
+     * plus signs.
      * @param string
      *            the string representation of an integer value.
      * @return the primitive integer value represented by {@code string}.
@@ -333,7 +336,8 @@
 
     /**
      * Parses the specified string as a signed integer value using the specified
-     * radix. The ASCII character \u002d ('-') is recognized as the minus sign.
+     * radix. The ASCII characters \u002d ('-') and \u002b ('+') are recognized
+     * as the minus and plus signs.
      *
      * @param string
      *            the string representation of an integer value.
@@ -350,19 +354,17 @@
         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
             throw new NumberFormatException("Invalid radix: " + radix);
         }
-        if (string == null) {
-            throw invalidInt(string);
-        }
-        int length = string.length(), i = 0;
-        if (length == 0) {
-            throw invalidInt(string);
-        }
-        boolean negative = string.charAt(i) == '-';
-        if (negative && ++i == length) {
+        if (string == null || string.isEmpty()) {
             throw invalidInt(string);
         }
 
-        return parse(string, i, radix, negative);
+        char firstChar = string.charAt(0);
+        int firstDigitIndex = (firstChar == '-' || firstChar == '+') ? 1 : 0;
+        if (firstDigitIndex == string.length()) {
+            throw invalidInt(string);
+        }
+
+        return parse(string, firstDigitIndex, radix, firstChar == '-');
     }
 
     /**
@@ -400,7 +402,8 @@
 
     private static int parse(String string, int offset, int radix, boolean negative) throws NumberFormatException {
         int max = Integer.MIN_VALUE / radix;
-        int result = 0, length = string.length();
+        int result = 0;
+        int length = string.length();
         while (offset < length) {
             int digit = Character.digit(string.charAt(offset++), radix);
             if (digit == -1) {
diff --git a/luni/src/main/java/java/lang/Long.java b/luni/src/main/java/java/lang/Long.java
index 4ebc85b..5c11564 100644
--- a/luni/src/main/java/java/lang/Long.java
+++ b/luni/src/main/java/java/lang/Long.java
@@ -127,8 +127,8 @@
     /**
      * Parses the specified string and returns a {@code Long} instance if the
      * string can be decoded into a long value. The string may be an optional
-     * minus sign "-" followed by a hexadecimal ("0x..." or "#..."), octal
-     * ("0..."), or decimal ("...") representation of a long.
+     * optional sign character ("-" or "+") followed by a hexadecimal ("0x..."
+     * or "#..."), octal ("0..."), or decimal ("...") representation of a long.
      *
      * @param string
      *            a string representation of a long value.
@@ -137,13 +137,15 @@
      *             if {@code string} cannot be parsed as a long value.
      */
     public static Long decode(String string) throws NumberFormatException {
-        int length = string.length(), i = 0;
+        int length = string.length();
         if (length == 0) {
             throw invalidLong(string);
         }
+
+        int i = 0;
         char firstDigit = string.charAt(i);
         boolean negative = firstDigit == '-';
-        if (negative) {
+        if (negative || firstDigit == '+') {
             if (length == 1) {
                 throw invalidLong(string);
             }
@@ -306,7 +308,8 @@
 
     /**
      * Parses the specified string as a signed decimal long value. The ASCII
-     * character \u002d ('-') is recognized as the minus sign.
+     * characters \u002d ('-') and \u002b ('+') are recognized as the minus and
+     * plus signs.
      *
      * @param string
      *            the string representation of a long value.
@@ -320,7 +323,8 @@
 
     /**
      * Parses the specified string as a signed long value using the specified
-     * radix. The ASCII character \u002d ('-') is recognized as the minus sign.
+     * radix. The ASCII characters \u002d ('-') and \u002b ('+') are recognized
+     * as the minus and plus signs.
      *
      * @param string
      *            the string representation of a long value.
@@ -337,24 +341,22 @@
         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
             throw new NumberFormatException("Invalid radix: " + radix);
         }
-        if (string == null) {
+        if (string == null || string.isEmpty()) {
             throw invalidLong(string);
         }
-        int length = string.length(), i = 0;
-        if (length == 0) {
-            throw invalidLong(string);
-        }
-        boolean negative = string.charAt(i) == '-';
-        if (negative && ++i == length) {
+        char firstChar = string.charAt(0);
+        int firstDigitIndex = (firstChar == '-' || firstChar == '+') ? 1 : 0;
+        if (firstDigitIndex == string.length()) {
             throw invalidLong(string);
         }
 
-        return parse(string, i, radix, negative);
+        return parse(string, firstDigitIndex, radix, firstChar == '-');
     }
 
     private static long parse(String string, int offset, int radix, boolean negative) {
         long max = Long.MIN_VALUE / radix;
-        long result = 0, length = string.length();
+        long result = 0;
+        int length = string.length();
         while (offset < length) {
             int digit = Character.digit(string.charAt(offset++), radix);
             if (digit == -1) {
diff --git a/luni/src/test/java/libcore/java/lang/IntegerTest.java b/luni/src/test/java/libcore/java/lang/IntegerTest.java
index c36afbb..b54b322 100644
--- a/luni/src/test/java/libcore/java/lang/IntegerTest.java
+++ b/luni/src/test/java/libcore/java/lang/IntegerTest.java
@@ -20,56 +20,114 @@
 
 public class IntegerTest extends junit.framework.TestCase {
 
-    public void test_SystemProperties() {
-        Properties originalProperties = System.getProperties();
-        try {
-            Properties testProperties = new Properties();
-            testProperties.put("testIncInt", "notInt");
-            System.setProperties(testProperties);
-            assertNull("returned incorrect default Integer",
-                Integer.getInteger("testIncInt"));
-            assertEquals(new Integer(4), Integer.getInteger("testIncInt", 4));
-            assertEquals(new Integer(4),
-                Integer.getInteger("testIncInt", new Integer(4)));
-        } finally {
-            System.setProperties(originalProperties);
-        }
+  public void testSystemProperties() {
+    Properties originalProperties = System.getProperties();
+    try {
+      Properties testProperties = new Properties();
+      testProperties.put("testIncInt", "notInt");
+      System.setProperties(testProperties);
+      assertNull("returned incorrect default Integer",
+        Integer.getInteger("testIncInt"));
+      assertEquals(new Integer(4), Integer.getInteger("testIncInt", 4));
+      assertEquals(new Integer(4),
+        Integer.getInteger("testIncInt", new Integer(4)));
+    } finally {
+      System.setProperties(originalProperties);
     }
+  }
 
-    public void test_compare() throws Exception {
-        final int min = Integer.MIN_VALUE;
-        final int zero = 0;
-        final int max = Integer.MAX_VALUE;
-        assertTrue(Integer.compare(max,  max)  == 0);
-        assertTrue(Integer.compare(min,  min)  == 0);
-        assertTrue(Integer.compare(zero, zero) == 0);
-        assertTrue(Integer.compare(max,  zero) > 0);
-        assertTrue(Integer.compare(max,  min)  > 0);
-        assertTrue(Integer.compare(zero, max)  < 0);
-        assertTrue(Integer.compare(zero, min)  > 0);
-        assertTrue(Integer.compare(min,  zero) < 0);
-        assertTrue(Integer.compare(min,  max)  < 0);
-    }
+  public void testCompare() throws Exception {
+    final int min = Integer.MIN_VALUE;
+    final int zero = 0;
+    final int max = Integer.MAX_VALUE;
+    assertTrue(Integer.compare(max,  max)  == 0);
+    assertTrue(Integer.compare(min,  min)  == 0);
+    assertTrue(Integer.compare(zero, zero) == 0);
+    assertTrue(Integer.compare(max,  zero) > 0);
+    assertTrue(Integer.compare(max,  min)  > 0);
+    assertTrue(Integer.compare(zero, max)  < 0);
+    assertTrue(Integer.compare(zero, min)  > 0);
+    assertTrue(Integer.compare(min,  zero) < 0);
+    assertTrue(Integer.compare(min,  max)  < 0);
+  }
 
-    public void test_parsePositiveInt() throws Exception {
-        assertEquals(0, Integer.parsePositiveInt("0", 10));
-        assertEquals(473, Integer.parsePositiveInt("473", 10));
-        assertEquals(255, Integer.parsePositiveInt("FF", 16));
+  public void testParseInt() throws Exception {
+    assertEquals(0, Integer.parseInt("+0", 10));
+    assertEquals(473, Integer.parseInt("+473", 10));
+    assertEquals(255, Integer.parseInt("+FF", 16));
+    assertEquals(102, Integer.parseInt("+1100110", 2));
+    assertEquals(2147483647, Integer.parseInt("+2147483647", 10));
+    assertEquals(411787, Integer.parseInt("Kona", 27));
+    assertEquals(411787, Integer.parseInt("+Kona", 27));
+    assertEquals(-145, Integer.parseInt("-145", 10));
 
-        try {
-            Integer.parsePositiveInt("-1", 10);
-            fail();
-        } catch (NumberFormatException e) {}
+    try {
+      Integer.parseInt("--1", 10); // multiple sign chars
+      fail();
+    } catch (NumberFormatException expected) {}
 
-        try {
-            Integer.parsePositiveInt("+1", 10);
-            fail();
-        } catch (NumberFormatException e) {}
+    try {
+      Integer.parseInt("++1", 10); // multiple sign chars
+      fail();
+    } catch (NumberFormatException expected) {}
 
-        try {
-            Integer.parsePositiveInt("+0", 16);
-            fail();
-        } catch (NumberFormatException e) {}
-    }
+    try {
+      Integer.parseInt("Kona", 10); // base too small
+      fail();
+    } catch (NumberFormatException expected) {}
+  }
+
+  public void testDecodeInt() throws Exception {
+    assertEquals(0, Integer.decode("+0").intValue());
+    assertEquals(473, Integer.decode("+473").intValue());
+    assertEquals(255, Integer.decode("+0xFF").intValue());
+    assertEquals(16, Integer.decode("+020").intValue());
+    assertEquals(2147483647, Integer.decode("+2147483647").intValue());
+    assertEquals(-73, Integer.decode("-73").intValue());
+    assertEquals(-255, Integer.decode("-0xFF").intValue());
+    assertEquals(255, Integer.decode("+#FF").intValue());
+    assertEquals(-255, Integer.decode("-#FF").intValue());
+
+    try {
+      Integer.decode("--1"); // multiple sign chars
+      fail();
+    } catch (NumberFormatException expected) {}
+
+    try {
+      Integer.decode("++1"); // multiple sign chars
+      fail();
+    } catch (NumberFormatException expected) {}
+
+    try {
+      Integer.decode("-+1"); // multiple sign chars
+      fail();
+    } catch (NumberFormatException expected) {}
+
+    try {
+      Integer.decode("Kona"); // invalid number
+      fail();
+    } catch (NumberFormatException expected) {}
+  }
+
+  public void testParsePositiveInt() throws Exception {
+    assertEquals(0, Integer.parsePositiveInt("0", 10));
+    assertEquals(473, Integer.parsePositiveInt("473", 10));
+    assertEquals(255, Integer.parsePositiveInt("FF", 16));
+
+    try {
+      Integer.parsePositiveInt("-1", 10);
+      fail();
+    } catch (NumberFormatException e) {}
+
+    try {
+      Integer.parsePositiveInt("+1", 10);
+      fail();
+    } catch (NumberFormatException e) {}
+
+    try {
+      Integer.parsePositiveInt("+0", 16);
+      fail();
+    } catch (NumberFormatException e) {}
+  }
 
 }
diff --git a/luni/src/test/java/libcore/java/lang/LongTest.java b/luni/src/test/java/libcore/java/lang/LongTest.java
index cb95518..0d1741a 100644
--- a/luni/src/test/java/libcore/java/lang/LongTest.java
+++ b/luni/src/test/java/libcore/java/lang/LongTest.java
@@ -20,7 +20,7 @@
 
 public class LongTest extends junit.framework.TestCase {
 
-    public void test_SystemProperties() {
+    public void testSystemProperties() {
         Properties originalProperties = System.getProperties();
         try {
             Properties testProperties = new Properties();
@@ -34,7 +34,7 @@
         }
     }
 
-    public void test_compare() throws Exception {
+    public void testCompare() throws Exception {
         final long min = Long.MIN_VALUE;
         final long zero = 0L;
         final long max = Long.MAX_VALUE;
@@ -49,7 +49,7 @@
         assertTrue(Long.compare(min,  max)  < 0);
     }
 
-    public void test_signum() throws Exception {
+    public void testSignum() throws Exception {
         assertEquals(0, Long.signum(0));
         assertEquals(1, Long.signum(1));
         assertEquals(-1, Long.signum(-1));
@@ -57,7 +57,7 @@
         assertEquals(-1, Long.signum(Long.MIN_VALUE));
     }
 
-    public void test_parsePositiveLong() throws Exception {
+    public void testParsePositiveLong() throws Exception {
         assertEquals(0, Long.parsePositiveLong("0", 10));
         assertEquals(473, Long.parsePositiveLong("473", 10));
         assertEquals(255, Long.parsePositiveLong("FF", 16));
@@ -78,4 +78,62 @@
         } catch (NumberFormatException e) {}
     }
 
+    public void testParseLong() throws Exception {
+        assertEquals(0, Long.parseLong("+0", 10));
+        assertEquals(473, Long.parseLong("+473", 10));
+        assertEquals(255, Long.parseLong("+FF", 16));
+        assertEquals(102, Long.parseLong("+1100110", 2));
+        assertEquals(Long.MAX_VALUE, Long.parseLong("+" + Long.MAX_VALUE, 10));
+        assertEquals(411787, Long.parseLong("Kona", 27));
+        assertEquals(411787, Long.parseLong("+Kona", 27));
+        assertEquals(-145, Long.parseLong("-145", 10));
+
+        try {
+            Long.parseLong("--1", 10); // multiple sign chars
+            fail();
+        } catch (NumberFormatException expected) {}
+
+        try {
+            Long.parseLong("++1", 10); // multiple sign chars
+            fail();
+        } catch (NumberFormatException expected) {}
+
+        try {
+            Long.parseLong("Kona", 10); // base to small
+            fail();
+        } catch (NumberFormatException expected) {}
+    }
+
+    public void testDecodeLong() throws Exception {
+        assertEquals(0, Long.decode("+0").longValue());
+        assertEquals(473, Long.decode("+473").longValue());
+        assertEquals(255, Long.decode("+0xFF").longValue());
+        assertEquals(16, Long.decode("+020").longValue());
+        assertEquals(Long.MAX_VALUE, Long.decode("+" + Long.MAX_VALUE).longValue());
+        assertEquals(-73, Long.decode("-73").longValue());
+        assertEquals(-255, Long.decode("-0xFF").longValue());
+        assertEquals(255, Long.decode("+#FF").longValue());
+        assertEquals(-255, Long.decode("-#FF").longValue());
+
+        try {
+            Long.decode("--1"); // multiple sign chars
+            fail();
+        } catch (NumberFormatException expected) {}
+
+        try {
+            Long.decode("++1"); // multiple sign chars
+            fail();
+        } catch (NumberFormatException expected) {}
+
+        try {
+            Long.decode("+-1"); // multiple sign chars
+            fail();
+        } catch (NumberFormatException expected) {}
+
+        try {
+            Long.decode("Kona"); // invalid number
+            fail();
+        } catch (NumberFormatException expected) {}
+    }
+
 }