Bug 825009 - Handles NaN and Infinity passed to .valueAsNumber. r=smaug
authorMounir Lamouri <mounir.lamouri@gmail.com>
Fri, 28 Dec 2012 12:48:41 +0000
changeset 126221 0bb4773db082c0ecf241e9dac3d8ca3402efbb13
parent 126220 3ff974766a3e324a7a10227613239c58ebecf7c2
child 126271 e19528d96c1aa51a5270f6e012ecf36a459136e7
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs825009
milestone20.0a1
first release with
nightly linux32
0bb4773db082 / 20.0a1 / 20121229030919 / files
nightly linux64
0bb4773db082 / 20.0a1 / 20121229030919 / files
nightly mac
0bb4773db082 / 20.0a1 / 20121229030919 / files
nightly win32
0bb4773db082 / 20.0a1 / 20121229030919 / files
nightly win64
0bb4773db082 / 20.0a1 / 20121229030919 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 825009 - Handles NaN and Infinity passed to .valueAsNumber. r=smaug
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/test/forms/test_valueasnumber_attribute.html
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -1198,27 +1198,36 @@ nsHTMLInputElement::GetList(nsIDOMHTMLEl
 
   CallQueryInterface(element, aValue);
   return NS_OK;
 }
 
 void
 nsHTMLInputElement::SetValue(double aValue)
 {
+  MOZ_ASSERT(!MOZ_DOUBLE_IS_INFINITE(aValue), "aValue must not be Infinity!");
+
+  if (MOZ_DOUBLE_IS_NaN(aValue)) {
+    SetValue(EmptyString());
+    return;
+  }
+
   nsAutoString value;
   ConvertNumberToString(aValue, value);
   SetValue(value);
 }
 
 bool
 nsHTMLInputElement::ConvertNumberToString(double aValue,
                                           nsAString& aResultString) const
 {
   MOZ_ASSERT(mType == NS_FORM_INPUT_DATE || mType == NS_FORM_INPUT_NUMBER,
              "ConvertNumberToString is only implemented for type='{number,date}'");
+  MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(aValue) && !MOZ_DOUBLE_IS_INFINITE(aValue),
+             "aValue must be a valid non-Infinite number.");
 
   aResultString.Truncate();
 
   switch (mType) {
     case NS_FORM_INPUT_NUMBER:
       aResultString.AppendFloat(aValue);
       return true;
     case NS_FORM_INPUT_DATE:
@@ -1315,16 +1324,22 @@ nsHTMLInputElement::GetValueAsNumber(dou
   *aValueAsNumber = DoesValueAsNumberApply() ? GetValueAsDouble()
                                              : MOZ_DOUBLE_NaN();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::SetValueAsNumber(double aValueAsNumber)
 {
+  // TODO: return TypeError when HTMLInputElement is converted to WebIDL, see
+  // bug 825197.
+  if (MOZ_DOUBLE_IS_INFINITE(aValueAsNumber)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
   if (!DoesValueAsNumberApply()) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   SetValue(aValueAsNumber);
   return NS_OK;
 }
 
--- a/content/html/content/test/forms/test_valueasnumber_attribute.html
+++ b/content/html/content/test/forms/test_valueasnumber_attribute.html
@@ -121,16 +121,18 @@ function checkNumberGet()
     ["", null], // the empty string is not a number
     ["foo", null],
     ["42,13", null], // comma can't be used as a decimal separator
   ];
 
   element.type = "number";
   for (data of testData) {
     element.value = data[0];
+
+    // Given that NaN != NaN, we have to use null when the expected value is NaN.
     if (data[1] != null) {
       is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
          "floating point representation of the value");
     } else {
       ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN "  +
          "when the element value is not a number");
     }
   }
@@ -143,30 +145,44 @@ function checkNumberSet()
     [42, "42"],
     [-42, "-42"], // should work for negative values
     [42.1234, "42.1234"],
     [123.123456789123, "123.123456789123"], // double precision
     [1e2, "100"], // e should be usable
     [2e1, "20"],
     [1e-1, "0.1"], // value after e can be negative
     [1E2, "100"], // E can be used instead of e
-    ["", null], // the empty string is not a number
-    ["foo", null],
+    // Setting a string will set NaN.
+    ["foo", ""],
+    // "" is converted to 0.
+    ["", 0],
+    [42, "42"], // Keep this here, it is used by the next test.
+    // Setting Infinity should throw and not change the current value.
+    [Infinity, 42, true],
+    [-Infinity, 42, true],
+    // Setting NaN should change the value to the empty string.
+    [NaN, ""],
   ];
 
   element.type = "number";
   for (data of testData) {
-    element.valueAsNumber = data[0];
-    if (data[1] != null) {
+    var caught = false;
+    try {
+      element.valueAsNumber = data[0];
       is(element.value, data[1],
          "valueAsNumber should be able to set the value");
+    } catch (e) {
+      caught = true;
+    }
+
+    if (data[2]) {
+      ok(caught, "valueAsNumber should have thrown");
+      is(element.value, data[1], "value should not have changed");
     } else {
-      element.valueAsNumber = testData[0];
-      isnot(element.value, data[1],
-            "valueAsNumber should not set the value if it's not a number");
+      ok(!caught, "valueAsNumber should not have thrown");
     }
   }
 }
 
 function checkDateGet()
 {
   var validData =
   [
@@ -241,22 +257,39 @@ function checkDateSet()
     [ false,             "1970-01-01" ],
     [ null,              "1970-01-01" ],
     // Those are converted to NaN, the corresponding date string is the empty string
     [ "invaliddatenumber", "" ],
     [ NaN,               "" ],
     [ undefined,         "" ],
     // Out of range, the corresponding date string is the empty string
     [ -62135596800001,   "" ],
+    // Infinity will keep the current value and throw (so we need to set a current value).
+    [ 1298851200010, "2011-02-28" ],
+    [ Infinity, "2011-02-28", true ],
+    [ -Infinity, "2011-02-28", true ],
   ];
 
   element.type = "date";
   for (data of testData) {
-    element.valueAsNumber = data[0];
-    is(element.value, data[1], "valueAsNumber should set the value to " + data[1]);
+    var caught = false;
+
+    try {
+      element.valueAsNumber = data[0];
+      is(element.value, data[1], "valueAsNumber should set the value to " + data[1]);
+    } catch(e) {
+      caught = true;
+    }
+
+    if (data[2]) {
+      ok(caught, "valueAsNumber should have trhown"); 
+      is(element.value, data[1], "the value should not have changed");
+    } else {
+      ok(!caught, "valueAsNumber should not have thrown");
+    }
   }
 
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
 checkAvailability();