Bug 1310077 - Implement the value sanitizing algorithm for <input type=datetime-local>. r=smaug
authorJessica Jong <jjong@mozilla.com>
Wed, 09 Nov 2016 23:48:00 -0500
changeset 352088 6ea6f245045920abf908f7cb3c5dc1f725f1a8f3
parent 352087 c04a775a0e698a8dc3449725aa5797a6bf6e2fc1
child 352089 93361acd5e006814f4a039fb429f378763a847ca
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1310077
milestone52.0a1
Bug 1310077 - Implement the value sanitizing algorithm for <input type=datetime-local>. r=smaug
dom/html/HTMLInputElement.cpp
dom/html/HTMLInputElement.h
dom/html/test/forms/test_input_sanitization.html
dom/html/test/forms/test_input_typing_sanitization.html
dom/html/test/test_bug590363.html
testing/web-platform/meta/html/semantics/forms/constraints/form-validation-validity-valueMissing.html.ini
testing/web-platform/meta/html/semantics/forms/the-input-element/datetime-local.html.ini
testing/web-platform/meta/html/semantics/forms/the-input-element/type-change-state.html.ini
testing/web-platform/meta/html/semantics/forms/the-input-element/valueMode.html.ini
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -5309,16 +5309,25 @@ HTMLInputElement::SanitizeValue(nsAStrin
       break;
     case NS_FORM_INPUT_WEEK:
       {
         if (!aValue.IsEmpty() && !IsValidWeek(aValue)) {
           aValue.Truncate();
         }
       }
       break;
+    case NS_FORM_INPUT_DATETIME_LOCAL:
+      {
+        if (!aValue.IsEmpty() && !IsValidDateTimeLocal(aValue)) {
+          aValue.Truncate();
+        } else {
+          NormalizeDateTimeLocal(aValue);
+        }
+      }
+      break;
     case NS_FORM_INPUT_COLOR:
       {
         if (IsValidSimpleColor(aValue)) {
           ToLowerCase(aValue);
         } else {
           // Set default (black) color, if aValue wasn't parsed correctly.
           aValue.AssignLiteral("#000000");
         }
@@ -5396,29 +5405,37 @@ HTMLInputElement::IsValidMonth(const nsA
 
 bool
 HTMLInputElement::IsValidDate(const nsAString& aValue) const
 {
   uint32_t year, month, day;
   return ParseDate(aValue, &year, &month, &day);
 }
 
-bool HTMLInputElement::ParseYear(const nsAString& aValue, uint32_t* aYear) const
+bool
+HTMLInputElement::IsValidDateTimeLocal(const nsAString& aValue) const
+{
+  uint32_t year, month, day, time;
+  return ParseDateTimeLocal(aValue, &year, &month, &day, &time);
+}
+
+bool
+HTMLInputElement::ParseYear(const nsAString& aValue, uint32_t* aYear) const
 {
   if (aValue.Length() < 4) {
     return false;
   }
 
   return DigitSubStringToNumber(aValue, 0, aValue.Length(), aYear) &&
       *aYear > 0;
 }
 
-bool HTMLInputElement::ParseMonth(const nsAString& aValue,
-                                  uint32_t* aYear,
-                                  uint32_t* aMonth) const
+bool
+HTMLInputElement::ParseMonth(const nsAString& aValue, uint32_t* aYear,
+                             uint32_t* aMonth) const
 {
   // Parse the year, month values out a string formatted as 'yyyy-mm'.
   if (aValue.Length() < 7) {
     return false;
   }
 
   uint32_t endOfYearOffset = aValue.Length() - 3;
   if (aValue[endOfYearOffset] != '-') {
@@ -5429,19 +5446,19 @@ bool HTMLInputElement::ParseMonth(const 
   if (!ParseYear(yearStr, aYear)) {
     return false;
   }
 
   return DigitSubStringToNumber(aValue, endOfYearOffset + 1, 2, aMonth) &&
          *aMonth > 0 && *aMonth <= 12;
 }
 
-bool HTMLInputElement::ParseWeek(const nsAString& aValue,
-                                 uint32_t* aYear,
-                                 uint32_t* aWeek) const
+bool
+HTMLInputElement::ParseWeek(const nsAString& aValue, uint32_t* aYear,
+                            uint32_t* aWeek) const
 {
   // Parse the year, month values out a string formatted as 'yyyy-Www'.
   if (aValue.Length() < 8) {
     return false;
   }
 
   uint32_t endOfYearOffset = aValue.Length() - 4;
   if (aValue[endOfYearOffset] != '-') {
@@ -5457,20 +5474,19 @@ bool HTMLInputElement::ParseWeek(const n
     return false;
   }
 
   return DigitSubStringToNumber(aValue, endOfYearOffset + 2, 2, aWeek) &&
          *aWeek > 0 && *aWeek <= MaximumWeekInYear(*aYear);
 
 }
 
-bool HTMLInputElement::ParseDate(const nsAString& aValue,
-                                 uint32_t* aYear,
-                                 uint32_t* aMonth,
-                                 uint32_t* aDay) const
+bool
+HTMLInputElement::ParseDate(const nsAString& aValue, uint32_t* aYear,
+                            uint32_t* aMonth, uint32_t* aDay) const
 {
 /*
  * Parse the year, month, day values out a date string formatted as 'yyyy-mm-dd'.
  * -The year must be 4 or more digits long, and year > 0
  * -The month must be exactly 2 digits long, and 01 <= month <= 12
  * -The day must be exactly 2 digit long, and 01 <= day <= maxday
  *  Where maxday is the number of days in the month 'month' and year 'year'
  */
@@ -5487,16 +5503,95 @@ bool HTMLInputElement::ParseDate(const n
   if (!ParseMonth(yearMonthStr, aYear, aMonth)) {
     return false;
   }
 
   return DigitSubStringToNumber(aValue, endOfMonthOffset + 1, 2, aDay) &&
          *aDay > 0 && *aDay <= NumberOfDaysInMonth(*aMonth, *aYear);
 }
 
+bool
+HTMLInputElement::ParseDateTimeLocal(const nsAString& aValue, uint32_t* aYear,
+                                     uint32_t* aMonth, uint32_t* aDay,
+                                     uint32_t* aTime) const
+{
+  // Parse the year, month, day and time values out a string formatted as
+  // 'yyyy-mm-ddThh:mm[:ss.s] or 'yyyy-mm-dd hh:mm[:ss.s]', where fractions of
+  // seconds can be 1 to 3 digits.
+  // The minimum length allowed is 16, which is of the form 'yyyy-mm-ddThh:mm'
+  // or 'yyyy-mm-dd hh:mm'.
+  if (aValue.Length() < 16) {
+    return false;
+  }
+
+  const uint32_t sepIndex = 10;
+  if (aValue[sepIndex] != 'T' && aValue[sepIndex] != ' ') {
+    return false;
+  }
+
+  const nsAString& dateStr = Substring(aValue, 0, sepIndex);
+  if (!ParseDate(dateStr, aYear, aMonth, aDay)) {
+    return false;
+  }
+
+  const nsAString& timeStr = Substring(aValue, sepIndex + 1,
+                                       aValue.Length() - sepIndex + 1);
+  if (!ParseTime(timeStr, aTime)) {
+    return false;
+  }
+
+  return true;
+}
+
+void
+HTMLInputElement::NormalizeDateTimeLocal(nsAString& aValue) const
+{
+  if (aValue.IsEmpty()) {
+    return;
+  }
+
+  // Use 'T' as the separator between date string and time string.
+  const uint32_t sepIndex = 10;
+  if (aValue[sepIndex] == ' ') {
+    aValue.Replace(sepIndex, 1, NS_LITERAL_STRING("T"));
+  }
+
+  // Time expressed as the shortest possible string.
+  if (aValue.Length() == 16) {
+    return;
+  }
+
+  // Fractions of seconds part is optional, ommit it if it's 0.
+  if (aValue.Length() > 19) {
+    uint32_t milliseconds;
+    if (!DigitSubStringToNumber(aValue, 20, aValue.Length() - 20,
+                                &milliseconds)) {
+      return;
+    }
+
+    if (milliseconds != 0) {
+      return;
+    }
+
+    aValue.Cut(19, aValue.Length() - 19);
+  }
+
+  // Seconds part is optional, ommit it if it's 0.
+  uint32_t seconds;
+  if (!DigitSubStringToNumber(aValue, 17, aValue.Length() - 17, &seconds)) {
+    return;
+  }
+
+  if (seconds != 0) {
+    return;
+  }
+
+  aValue.Cut(16, aValue.Length() - 16);
+}
+
 double
 HTMLInputElement::DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const
 {
   double days = JS::DayFromYear(aYear) + (aWeek - 1) * 7;
   uint32_t dayOneIsoWeekday = DayOfWeek(aYear, 1, 1, true);
 
   // If day one of that year is on/before Thursday, we should subtract the
   // days that belong to last year in our first week, otherwise, our first
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1208,16 +1208,26 @@ protected:
    * Parse a date string of the form yyyy-mm-dd
    * @param the string to be parsed.
    * @return whether the string is a valid date.
    * Note : this function does not consider the empty string as valid.
    */
   bool IsValidDate(const nsAString& aValue) const;
 
   /**
+   * Parse a datetime-local string of the form yyyy-mm-ddThh:mm[:ss.s] or
+   * yyyy-mm-dd hh:mm[:ss.s], where fractions of seconds can be 1 to 3 digits.
+   *
+   * @param the string to be parsed.
+   * @return whether the string is a valid datetime-local string.
+   * Note : this function does not consider the empty string as valid.
+   */
+  bool IsValidDateTimeLocal(const nsAString& aValue) const;
+
+  /**
    * Parse a year string of the form yyyy
    *
    * @param the string to be parsed.
    *
    * @return the year in aYear.
    * @return whether the parsing was successful.
    */
   bool ParseYear(const nsAString& aValue, uint32_t* aYear) const;
@@ -1251,16 +1261,36 @@ protected:
    * @return whether the parsing was successful.
    */
   bool ParseDate(const nsAString& aValue,
                  uint32_t* aYear,
                  uint32_t* aMonth,
                  uint32_t* aDay) const;
 
   /**
+   * Parse a datetime-local string of the form yyyy-mm-ddThh:mm[:ss.s] or
+   * yyyy-mm-dd hh:mm[:ss.s], where fractions of seconds can be 1 to 3 digits.
+   *
+   * @param the string to be parsed.
+   * @return the date in aYear, aMonth, aDay and time expressed in milliseconds
+   *         in aTime.
+   * @return whether the parsing was successful.
+   */
+  bool ParseDateTimeLocal(const nsAString& aValue,
+                          uint32_t* aYear,
+                          uint32_t* aMonth,
+                          uint32_t* aDay,
+                          uint32_t* aTime) const;
+
+  /**
+   * Normalize the datetime-local string following the HTML specifications:
+   * https://html.spec.whatwg.org/multipage/infrastructure.html#valid-normalised-local-date-and-time-string
+   */
+  void NormalizeDateTimeLocal(nsAString& aValue) const;
+  /**
    * This methods returns the number of days since epoch for a given year and
    * week.
    */
   double DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const;
 
   /**
    * This methods returns the number of days in a given month, for a given year.
    */
--- a/dom/html/test/forms/test_input_sanitization.html
+++ b/dom/html/test/forms/test_input_sanitization.html
@@ -69,25 +69,138 @@ function flushDelayedTests(description)
 }
 
 // We are excluding "file" because it's too different from the other types.
 // And it has no sanitizing algorithm.
 var inputTypes =
 [
   "text", "password", "search", "tel", "hidden", "checkbox", "radio",
   "submit", "image", "reset", "button", "email", "url", "number", "date",
-  "time", "range", "color", "month", "week",
+  "time", "range", "color", "month", "week", "datetime-local"
 ];
 
 var valueModeValue =
 [
   "text", "search", "url", "tel", "email", "password", "date", "datetime",
   "month", "week", "time", "datetime-local", "number", "range", "color",
 ];
 
+function sanitizeDate(aValue)
+{
+  // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-date-string
+  function getNumbersOfDaysInMonth(aMonth, aYear) {
+    if (aMonth === 2) {
+      return (aYear % 400 === 0 || (aYear % 100 != 0 && aYear % 4 === 0)) ? 29 : 28;
+    }
+    return (aMonth === 1 || aMonth === 3 || aMonth === 5 || aMonth === 7 ||
+            aMonth === 8 || aMonth === 10 || aMonth === 12) ? 31 : 30;
+  }
+
+  var match = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})$/.exec(aValue);
+  if (!match) {
+    return "";
+  }
+  var year = Number(match[1]);
+  if (year === 0) {
+    return "";
+  }
+  var month = Number(match[2]);
+  if (month > 12 || month < 1) {
+    return "";
+  }
+  var day = Number(match[3]);
+  return 1 <= day && day <= getNumbersOfDaysInMonth(month, year) ? aValue : "";
+}
+
+function sanitizeTime(aValue)
+{
+  // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-time-string
+  var match = /^([0-9]{2}):([0-9]{2})(.*)$/.exec(aValue);
+  if (!match) {
+    return "";
+  }
+  var hours = match[1];
+  if (hours < 0 || hours > 23) {
+    return "";
+  }
+  var minutes = match[2];
+  if (minutes < 0 || minutes > 59) {
+    return "";
+  }
+  var other = match[3];
+  if (other == "") {
+    return aValue;
+  }
+  match = /^:([0-9]{2})(.*)$/.exec(other);
+  if (!match) {
+    return "";
+  }
+  var seconds = match[1];
+  if (seconds < 0 || seconds > 59) {
+    return "";
+  }
+  var other = match[2];
+  if (other == "") {
+    return aValue;
+  }
+  match = /^.([0-9]{1,3})$/.exec(other);
+  if (!match) {
+    return "";
+  }
+  return aValue;
+}
+
+function sanitizeDateTimeLocal(aValue)
+{
+  // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-local-date-and-time-string
+  if (aValue.length < 16) {
+    return "";
+  }
+
+  var separator = aValue[10];
+  if (separator != "T" && separator != " ") {
+    return "";
+  }
+
+  var [date, time] = aValue.split(separator);
+  if (!sanitizeDate(date)) {
+    return "";
+  }
+
+  if (!sanitizeTime(time)) {
+    return "";
+  }
+
+  // Normalize datetime-local string.
+  // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-normalised-local-date-and-time-string
+  if (separator == " ") {
+    aValue = date + "T" + time;
+  }
+
+  if (aValue.length == 16) {
+    return aValue;
+  }
+
+  if (aValue.length > 19) {
+    var milliseconds = aValue.substring(20);
+    if (Number(milliseconds) != 0) {
+      return aValue;
+    }
+    aValue = aValue.slice(0, 19);
+  }
+
+  var seconds = aValue.substring(17);
+  if (Number(seconds) != 0) {
+    return aValue;
+  }
+  aValue = aValue.slice(0, 16);
+
+  return aValue;
+}
+
 function sanitizeValue(aType, aValue)
 {
   // http://www.whatwg.org/html/#value-sanitization-algorithm
   switch (aType) {
     case "text":
     case "password":
     case "search":
     case "tel":
@@ -107,74 +220,19 @@ function sanitizeValue(aType, aValue)
       if (value < defaultMinimum) {
         return defaultMinimum.toString();
       }
       if (value > defaultMaximum) {
         return defaultMaximum.toString();
       }
       return aValue;
     case "date":
-      // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-date-string
-      function getNumbersOfDaysInMonth(aMonth, aYear) {
-        if (aMonth === 2) {
-          return (aYear % 400 === 0 || (aYear % 100 != 0 && aYear % 4 === 0)) ? 29 : 28;
-        }
-        return (aMonth === 1 || aMonth === 3 || aMonth === 5 || aMonth === 7 ||
-                aMonth === 8 || aMonth === 10 || aMonth === 12) ? 31 : 30;
-      }
-
-      var match = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})$/.exec(aValue);
-      if (!match) {
-        return "";
-      }
-      var year = Number(match[1]);
-      if (year === 0) {
-        return "";
-      }
-      var month = Number(match[2]);
-      if (month > 12 || month < 1) {
-        return "";
-      }
-      var day = Number(match[3]);
-      return 1 <= day && day <= getNumbersOfDaysInMonth(month, year) ? aValue : "";
+      return sanitizeDate(aValue);
     case "time":
-      // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-time-string
-      var match = /^([0-9]{2}):([0-9]{2})(.*)$/.exec(aValue);
-      if (!match) {
-        return "";
-      }
-      var hours = match[1];
-      if (hours < 0 || hours > 23) {
-        return "";
-      }
-      var minutes = match[2];
-      if (minutes < 0 || minutes > 59) {
-        return "";
-      }
-      var other = match[3];
-      if (other == "") {
-        return aValue;
-      }
-      match = /^:([0-9]{2})(.*)$/.exec(other);
-      if (!match) {
-        return "";
-      }
-      var seconds = match[1];
-      if (seconds < 0 || seconds > 59) {
-        return "";
-      }
-      var other = match[2];
-      if (other == "") {
-        return aValue;
-      }
-      match = /^.([0-9]{1,3})$/.exec(other);
-      if (!match) {
-        return "";
-      }
-      return aValue;
+      return sanitizeTime(aValue);
     case "month":
       // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-month-string
       var match = /^([0-9]{4,})-([0-9]{2})$/.exec(aValue);
       if (!match) {
         return "";
       }
       var year = Number(match[1]);
       if (year === 0) {
@@ -211,21 +269,18 @@ function sanitizeValue(aType, aValue)
       if (year === 0) {
         return "";
       }
       var week = Number(match[2]);
       if (week > 53 || month < 1) {
         return "";
       }
       return 1 <= week && week <= getMaximumWeekInYear(year) ? aValue : "";
-    case "datetime":
     case "datetime-local":
-      // TODO: write the sanitize algorithm.
-      ok(false);
-      return "";
+      return sanitizeDateTimeLocal(aValue);
     case "color":
       return /^#[0-9A-Fa-f]{6}$/.exec(aValue) ? aValue.toLowerCase() : "#000000";
     default:
       return aValue;
   }
 }
 
 function checkSanitizing(element, inputTypeDescription)
@@ -406,16 +461,41 @@ function checkSanitizing(element, inputT
     "16-W30",
     "2016-Week30",
     "2000-100",
     "0000-W01",
     "00-W01",
     "123456-W05",
     "1985-W100",
     "week",
+    // For datetime-local
+    "1970-01-01T00:00",
+    "1970-01-01Z12:00",
+    "1970-01-01 00:00:00",
+    "1970-01-01T00:00:00.0",
+    "1970-01-01T00:00:00.00",
+    "1970-01-01T00:00:00.000",
+    "1970-01-01 00:00:00.20",
+    "1234567-01-01T12:00",
+    "2016-13-01T12:00",
+    "2016-12-32T12:00",
+    "2016-11-08 15:40:30.0",
+    "2016-11-08T15:40:30.00",
+    "2016-11-07T17:30:10",
+    "2016-12-1T12:45",
+    "2016-12-01T12:45:30.123456",
+    "2016-12-01T24:00",
+    "2016-12-01T12:88:30",
+    "2016-12-01T12:30:99",
+    "2016-12-01T12:30:100",
+    "2016-12-01",
+    "2016-12-01T",
+    "2016-Dec-01T00:00",
+    "12-05-2016T00:00",
+    "datetime-local"
   ];
 
   for (value of testData) {
     element.setAttribute('value', value);
     delayed_is(element.value, sanitizeValue(type, value),
        "The value has not been correctly sanitized for type=" + type);
     delayed_is(element.getAttribute('value'), value,
        "The content value should not have been sanitized");
--- a/dom/html/test/forms/test_input_typing_sanitization.html
+++ b/dom/html/test/forms/test_input_typing_sanitization.html
@@ -190,16 +190,34 @@ function runTest()
         'week',
         '2016-30',
         '2010-W80',
         '2000/W30',
         '1985-W00',
         '1000-W'
       ]
     },
+    {
+      type: 'datetime-local',
+      validData: [
+        '0001-01-01T00:00',
+        '2016-11-07T16:45',
+        '2016-11-07T16:45:30',
+        '2016-11-07T16:45:30.10',
+        '2016-11-07T16:45:00.111',
+      ],
+      invalidData: [
+        '1-01-01T00:00',
+        '1970-01-01T9:30',
+        '2016/11/07T16:45',
+        '2016-11-07T16.45',
+        'T',
+        'datetime-local'
+      ]
+    },
   ];
 
   for (test of data) {
     gCurrentTest = test;
 
     input.type = test.type;
     gValidData = test.validData;
     gInvalidData = test.invalidData;
--- a/dom/html/test/test_bug590363.html
+++ b/dom/html/test/test_bug590363.html
@@ -40,41 +40,43 @@ var testData = [
   [ "range",    true ],
   [ "color",    true ],
   [ 'month',    true ],
   [ 'week',     true ],
   [ 'datetime-local', true ]
   // 'file' is treated separatly.
 ];
 
-var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color', 'month', 'week' ];
+var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color', 'month', 'week',
+                             'datetime-local' ];
 
 var length = testData.length;
 for (var i=0; i<length; ++i) {
   for (var j=0; j<length; ++j) {
     var e = document.createElement('input');
     e.type = testData[i][0];
 
     var expectedValue;
 
     // range will sanitize its value to 50 (the default) if it isn't a valid
     // number. We need to handle that specially.
     if (testData[j][0] == 'range' || testData[i][0] == 'range') {
       if (testData[j][0] == 'date' || testData[j][0] == 'time' ||
-          testData[j][0] == 'month' || testData[j][0] == 'week') {
+          testData[j][0] == 'month' || testData[j][0] == 'week' ||
+          testData[j][0] == 'datetime-local') {
         expectedValue = '';
       } else if (testData[j][0] == 'color') {
         expectedValue = '#000000';
       } else {
         expectedValue = '50';
       }
     } else if (testData[i][0] == 'color' || testData[j][0] == 'color') {
         if (testData[j][0] == 'number' || testData[j][0] == 'date' ||
             testData[j][0] == 'time' || testData[j][0] == 'month' ||
-            testData[j][0] == 'week') {
+            testData[j][0] == 'week' || testData[j][0] == 'datetime-local') {
           expectedValue = ''
         } else {
           expectedValue = '#000000';
         }
     } else if (nonTrivialSanitizing.indexOf(testData[i][0]) != -1 &&
                nonTrivialSanitizing.indexOf(testData[j][0]) != -1) {
       expectedValue = '';
     } else if (testData[i][0] == 'number' || testData[j][0] == 'number') {
@@ -82,16 +84,19 @@ for (var i=0; i<length; ++i) {
     } else if (testData[i][0] == 'date' || testData[j][0] == 'date') {
       expectedValue = '2012-12-21';
     } else if (testData[i][0] == 'time' || testData[j][0] == 'time') {
       expectedValue = '21:21';
     } else if (testData[i][0] == 'month' || testData[j][0] == 'month') {
       expectedValue = '2013-03';
     } else if (testData[i][0] == 'week' || testData[j][0] == 'week') {
       expectedValue = '2016-W35';
+    } else if (testData[i][0] == 'datetime-local' ||
+               testData[j][0] == 'datetime-local') {
+      expectedValue = '2016-11-07T16:40';
     } else {
       expectedValue = "foo";
     }
     e.value = expectedValue;
 
     e.type = testData[j][0];
     is(e.value, expectedValue, ".value should still return the same value after " +
        "changing type from " + testData[i][0] + " to " + testData[j][0]);
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-validity-valueMissing.html.ini
+++ /dev/null
@@ -1,23 +0,0 @@
-[form-validation-validity-valueMissing.html]
-  type: testharness
-  [[INPUT in DATETIME status\] The datetime type must be supported.]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] The datetime-local type must be supported.]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] The value attribute is a number(1234567)]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] The value attribute is a Date object]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] Invalid local date and time string(1979-10-99 99:99)]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] Invalid local date and time string(2001-12-21  12:00)-two white space]
-    expected: FAIL
-
-  [[INPUT in DATETIME-LOCAL status\] the value attribute is a string(abc)]
-    expected: FAIL
-
--- a/testing/web-platform/meta/html/semantics/forms/the-input-element/datetime-local.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/the-input-element/datetime-local.html.ini
@@ -1,29 +1,8 @@
 [datetime-local.html]
   type: testharness
-  [datetime-local input value set to 2014-01-01 11:11:11.111 without min/max]
-    expected: FAIL
-
-  [datetime-local input value set to 2014-01-01 11:11 without min/max]
-    expected: FAIL
-
-  [datetime-local input value set to 2014-01-01 00:00:00.000 without min/max]
-    expected: FAIL
-
-  [datetime-local input value set to 2014-01-0 11:11 without min/max]
-    expected: FAIL
-
-  [datetime-local input value set to 2014-01-01 11:1 without min/max]
-    expected: FAIL
-
-  [Value >= min attribute]
-    expected: FAIL
-
   [Value < min attribute]
     expected: FAIL
 
-  [Value <= max attribute]
-    expected: FAIL
-
   [Value > max attribute]
     expected: FAIL
 
--- a/testing/web-platform/meta/html/semantics/forms/the-input-element/type-change-state.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/the-input-element/type-change-state.html.ini
@@ -496,17 +496,17 @@
     expected: FAIL
 
   [change state from file to email]
     expected: FAIL
 
   [change state from file to password]
     expected: FAIL
 
-  [change state from file to datetime]
+  [change state from file to datetime-local]
     expected: FAIL
 
   [change state from file to date]
     expected: FAIL
 
   [change state from file to month]
     expected: FAIL
 
@@ -550,38 +550,35 @@
     expected: FAIL
 
   [change state from reset to datetime]
     expected: FAIL
 
   [change state from button to datetime]
     expected: FAIL
 
-  [change state from hidden to datetime-local]
+  [change state from datetime-local to hidden]
     expected: FAIL
 
-  [change state from text to datetime-local]
+  [change state from datetime-local to text]
     expected: FAIL
 
-  [change state from search to datetime-local]
+  [change state from datetime-local to search]
     expected: FAIL
 
-  [change state from tel to datetime-local]
-    expected: FAIL
-
-  [change state from url to datetime-local]
+  [change state from datetime-local to tel]
     expected: FAIL
 
-  [change state from email to datetime-local]
+  [change state from datetime-local to url]
     expected: FAIL
 
-  [change state from password to datetime-local]
+  [change state from datetime-local to email]
     expected: FAIL
 
-  [change state from datetime-local to hidden]
+  [change state from datetime-local to password]
     expected: FAIL
 
   [change state from datetime-local to checkbox]
     expected: FAIL
 
   [change state from datetime-local to radio]
     expected: FAIL
 
@@ -591,36 +588,8 @@
   [change state from datetime-local to image]
     expected: FAIL
 
   [change state from datetime-local to reset]
     expected: FAIL
 
   [change state from datetime-local to button]
     expected: FAIL
-
-  [change state from range to datetime-local]
-    expected: FAIL
-
-  [change state from color to datetime-local]
-    expected: FAIL
-
-  [change state from checkbox to datetime-local]
-    expected: FAIL
-
-  [change state from radio to datetime-local]
-    expected: FAIL
-
-  [change state from file to datetime-local]
-    expected: FAIL
-
-  [change state from submit to datetime-local]
-    expected: FAIL
-
-  [change state from image to datetime-local]
-    expected: FAIL
-
-  [change state from reset to datetime-local]
-    expected: FAIL
-
-  [change state from button to datetime-local]
-    expected: FAIL
-
--- a/testing/web-platform/meta/html/semantics/forms/the-input-element/valueMode.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/the-input-element/valueMode.html.ini
@@ -42,15 +42,8 @@
   [value IDL attribute of input type reset with value attribute]
     expected: FAIL
 
   [value IDL attribute of input type button without value attribute]
     expected: FAIL
 
   [value IDL attribute of input type button with value attribute]
     expected: FAIL
-
-  [value IDL attribute of input type datetime-local without value attribute]
-    expected: FAIL
-
-  [value IDL attribute of input type datetime-local with value attribute]
-    expected: FAIL
-