Fix handling of -0 in Math.copySign

Change-Id: I3cbae4d357763a96400c0e3ada7646b151728ba9
diff --git a/user/super/com/google/gwt/emul/java/lang/Math.java b/user/super/com/google/gwt/emul/java/lang/Math.java
index 82463fa..15bc14c 100644
--- a/user/super/com/google/gwt/emul/java/lang/Math.java
+++ b/user/super/com/google/gwt/emul/java/lang/Math.java
@@ -102,11 +102,11 @@
   }
 
   public static double copySign(double magnitude, double sign) {
-    if (sign < 0) {
-      return (magnitude < 0) ? magnitude : -magnitude;
-    } else {
-      return (magnitude > 0) ? magnitude : -magnitude;
-    }
+    return isNegative(sign) ? -Math.abs(magnitude) : Math.abs(magnitude);
+  }
+
+  private static boolean isNegative(double d) {
+    return d < 0 || 1 / d < 0;
   }
 
   public static float copySign(float magnitude, float sign) {
diff --git a/user/test/com/google/gwt/emultest/java/lang/MathTest.java b/user/test/com/google/gwt/emultest/java/lang/MathTest.java
index c47d4ff..ed3ac23 100644
--- a/user/test/com/google/gwt/emultest/java/lang/MathTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/MathTest.java
@@ -33,6 +33,15 @@
   private static final Integer[] ALL_INTEGER_CANDIDATES = getAllIntegerCandidates();
   private static final Long[] ALL_LONG_CANDIDATES = getAllLongCandidates();
 
+  private static void assertNegativeZero(double x) {
+    assertTrue(isNegativeZero(x));
+  }
+
+  private static void assertPositiveZero(double x) {
+    assertEquals(0.0, x);
+    assertFalse(isNegativeZero(x));
+  }
+
   private static boolean isNegativeZero(double x) {
     return Double.doubleToLongBits(-0.0) == Double.doubleToLongBits(x);
   }
@@ -54,10 +63,9 @@
     v = Math.abs(1.0);
     assertEquals(1.0, v);
     v = Math.abs(negativeZero);
-    assertEquals(0.0, v);
-    assertFalse(isNegativeZero(v));
+    assertPositiveZero(v);
     v = Math.abs(0.0);
-    assertEquals(0.0, v);
+    assertPositiveZero(v);
     v = Math.abs(Double.NEGATIVE_INFINITY);
     assertEquals(Double.POSITIVE_INFINITY, v);
     v = Math.abs(Double.POSITIVE_INFINITY);
@@ -101,6 +109,41 @@
     assertEquals(10.0, v, 1e-7);
   }
 
+  public void testCopySign() {
+    double negativeZero = makeNegativeZero();
+
+    assertEquals(3.0, Math.copySign(3.0, 2.0));
+    assertEquals(3.0, Math.copySign(-3.0, 2.0));
+    assertEquals(-3.0, Math.copySign(3.0, -2.0));
+    assertEquals(-3.0, Math.copySign(-3.0, -2.0));
+
+    assertEquals(2.0, Math.copySign(2.0, 0.0));
+    assertEquals(2.0, Math.copySign(-2.0, 0.0));
+    assertEquals(-2.0, Math.copySign(2.0, negativeZero));
+    assertEquals(-2.0, Math.copySign(-2.0, negativeZero));
+    assertEquals(-2.0, Math.copySign(-2.0, Double.NEGATIVE_INFINITY));
+    assertEquals(2.0, Math.copySign(-2.0, Double.POSITIVE_INFINITY));
+    assertEquals(2.0, Math.copySign(-2.0, Double.NaN));
+
+    assertPositiveZero(Math.copySign(0.0, 4.0));
+    assertPositiveZero(Math.copySign(negativeZero, 4.0));
+    assertNegativeZero(Math.copySign(0.0, -4.0));
+    assertNegativeZero(Math.copySign(negativeZero, -4.0));
+
+    assertPositiveZero(Math.copySign(0.0, 0.0));
+    assertPositiveZero(Math.copySign(negativeZero, 0.0));
+    assertNegativeZero(Math.copySign(0.0, negativeZero));
+    assertNegativeZero(Math.copySign(negativeZero, negativeZero));
+
+    assertEquals(Double.POSITIVE_INFINITY, Math.copySign(Double.POSITIVE_INFINITY, 1));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.copySign(Double.POSITIVE_INFINITY, -1));
+    assertEquals(Double.POSITIVE_INFINITY, Math.copySign(Double.NEGATIVE_INFINITY, 1));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.copySign(Double.NEGATIVE_INFINITY, -1));
+
+    assertEquals(Double.NaN, Math.copySign(Double.NaN, 1), 0);
+    assertEquals(Double.NaN, Math.copySign(Double.NaN, -1), 0);
+  }
+
   public void testCos() {
     double v = Math.cos(0.0);
     assertEquals(1.0, v, 1e-7);