зеркало из https://github.com/mozilla/gecko-dev.git
416 строки
11 KiB
HTML
416 строки
11 KiB
HTML
<!DOCTYPE HTML>
|
|
<html>
|
|
<!--
|
|
https://bugzilla.mozilla.org/show_bug.cgi?id=549475
|
|
-->
|
|
<head>
|
|
<title>Test for Bug 549475</title>
|
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
|
</head>
|
|
<body>
|
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=549475">Mozilla Bug 549475</a>
|
|
<p id="display"></p>
|
|
<pre id="test">
|
|
<div id='content'>
|
|
<form>
|
|
</form>
|
|
</div>
|
|
<script type="application/javascript">
|
|
|
|
/**
|
|
* This files tests the 'value sanitization algorithm' for the various input
|
|
* types. Note that an input's value is affected by more than just its type's
|
|
* value sanitization algorithm; e.g. some type=range has actions that the user
|
|
* agent must perform to change the element's value to avoid underflow/overflow
|
|
* and step mismatch (when possible). We specifically avoid triggering these
|
|
* other actions here so that this test only tests the value sanitization
|
|
* algorithm for the various input types.
|
|
*
|
|
* XXXjwatt splitting out testing of the value sanitization algorithm and
|
|
* "other things" that affect .value makes it harder to know what we're testing
|
|
* and what we've missed, because what's included in the value sanitization
|
|
* algorithm and what's not is different from input type to input type. It
|
|
* seems to me it would be better to have a test (maybe one per type) focused
|
|
* on testing .value for permutations of all other inputs that can affect it.
|
|
* The value sanitization algorithm is just an internal spec concept after all.
|
|
*/
|
|
|
|
// We buffer up the results of sets of sub-tests, and avoid outputting log
|
|
// entries for them all if they all pass. Otherwise, we have an enormous amount
|
|
// of test output.
|
|
|
|
var delayedTests = [];
|
|
var anyFailedDelayedTests = false;
|
|
|
|
function delayed_is(actual, expected, description)
|
|
{
|
|
var result = actual == expected;
|
|
delayedTests.push({ actual: actual, expected: expected, description: description });
|
|
if (!result) {
|
|
anyFailedDelayedTests = true;
|
|
}
|
|
}
|
|
|
|
function flushDelayedTests(description)
|
|
{
|
|
if (anyFailedDelayedTests) {
|
|
info("Outputting individual results for \"" + description + "\" due to failures in subtests");
|
|
for (var test of delayedTests) {
|
|
is(test.actual, test.expected, test.description);
|
|
}
|
|
} else {
|
|
ok(true, description + " (" + delayedTests.length + " subtests)");
|
|
}
|
|
delayedTests = [];
|
|
anyFailedDelayedTests = false;
|
|
}
|
|
|
|
// 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"
|
|
];
|
|
|
|
var todoTypes =
|
|
[
|
|
"month", "week", "datetime", "datetime-local",
|
|
];
|
|
|
|
var valueModeValue =
|
|
[
|
|
"text", "search", "url", "tel", "email", "password", "date", "datetime",
|
|
"month", "week", "time", "datetime-local", "number", "range", "color",
|
|
];
|
|
|
|
function sanitizeValue(aType, aValue)
|
|
{
|
|
// http://www.whatwg.org/html/#value-sanitization-algorithm
|
|
switch (aType) {
|
|
case "text":
|
|
case "password":
|
|
case "search":
|
|
case "tel":
|
|
return aValue.replace(/[\n\r]/g, "");
|
|
case "url":
|
|
case "email":
|
|
return aValue.replace(/[\n\r]/g, "").replace(/^[\u0020\u0009\t\u000a\u000c\u000d]+|[\u0020\u0009\t\u000a\u000c\u000d]+$/g, "");
|
|
case "number":
|
|
return isNaN(Number(aValue)) ? "" : aValue;
|
|
case "range":
|
|
var defaultMinimum = 0;
|
|
var defaultMaximum = 100;
|
|
var value = Number(aValue);
|
|
if (isNaN(value)) {
|
|
return ((defaultMaximum - defaultMinimum)/2).toString(); // "50"
|
|
}
|
|
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 : "";
|
|
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;
|
|
case "month":
|
|
case "week":
|
|
case "datetime":
|
|
case "datetime-local":
|
|
// TODO: write the sanitize algorithm.
|
|
ok(false);
|
|
return "";
|
|
case "color":
|
|
return /^#[0-9A-Fa-f]{6}$/.exec(aValue) ? aValue.toLowerCase() : "#000000";
|
|
default:
|
|
return aValue;
|
|
}
|
|
}
|
|
|
|
function checkSanitizing(element, inputTypeDescription)
|
|
{
|
|
var testData =
|
|
[
|
|
// For text, password, search, tel, email:
|
|
"\n\rfoo\n\r",
|
|
"foo\n\rbar",
|
|
" foo ",
|
|
" foo\n\r bar ",
|
|
// For url:
|
|
"\r\n foobar \n\r",
|
|
"\u000B foo \u000B",
|
|
"\u000A foo \u000A",
|
|
"\u000C foo \u000C",
|
|
"\u000d foo \u000d",
|
|
"\u0020 foo \u0020",
|
|
" \u0009 foo \u0009 ",
|
|
// For number and range:
|
|
"42",
|
|
"13.37",
|
|
"1.234567898765432",
|
|
"12foo",
|
|
"1e2",
|
|
"3E42",
|
|
// For date:
|
|
"1970-01-01",
|
|
"1234-12-12",
|
|
"1234567890-01-02",
|
|
"2012-12-31",
|
|
"2012-02-29",
|
|
"2000-02-29",
|
|
"1234",
|
|
"1234-",
|
|
"12345",
|
|
"1234-01",
|
|
"1234-012",
|
|
"1234-01-",
|
|
"12-12",
|
|
"999-01-01",
|
|
"1234-56-78-91",
|
|
"1234-567-78",
|
|
"1234--7-78",
|
|
"abcd-12-12",
|
|
"thisinotadate",
|
|
"2012-13-01",
|
|
"1234-12-42",
|
|
" 2012-13-01",
|
|
" 123-01-01",
|
|
"2012- 3-01",
|
|
"12- 10- 01",
|
|
" 12-0-1",
|
|
"2012-3-001",
|
|
"2012-12-00",
|
|
"2012-12-1r",
|
|
"2012-11-31",
|
|
"2011-02-29",
|
|
"2100-02-29",
|
|
"a2000-01-01",
|
|
"2000a-01-0'",
|
|
"20aa00-01-01",
|
|
"2000a2000-01-01",
|
|
"2000-1-1",
|
|
"2000-1-01",
|
|
"2000-01-1",
|
|
"2000-01-01 ",
|
|
"2000- 01-01",
|
|
"-1970-01-01",
|
|
"0000-00-00",
|
|
"0001-00-00",
|
|
"0000-01-01",
|
|
"1234-12 12",
|
|
"1234 12-12",
|
|
"1234 12 12",
|
|
// For time:
|
|
"1",
|
|
"10",
|
|
"10:",
|
|
"10:1",
|
|
"21:21",
|
|
":21:21",
|
|
"-21:21",
|
|
" 21:21",
|
|
"21-21",
|
|
"21:21:",
|
|
"21:211",
|
|
"121:211",
|
|
"21:21 ",
|
|
"00:00",
|
|
"-1:00",
|
|
"24:00",
|
|
"00:60",
|
|
"01:01",
|
|
"23:59",
|
|
"99:99",
|
|
"8:30",
|
|
"19:2",
|
|
"19:a2",
|
|
"4c:19",
|
|
"10:.1",
|
|
"1.:10",
|
|
"13:37:42",
|
|
"13:37.42",
|
|
"13:37:42 ",
|
|
"13:37:42.",
|
|
"13:37:61.",
|
|
"13:37:00",
|
|
"13:37:99",
|
|
"13:37:b5",
|
|
"13:37:-1",
|
|
"13:37:.1",
|
|
"13:37:1.",
|
|
"13:37:42.001",
|
|
"13:37:42.001",
|
|
"13:37:42.abc",
|
|
"13:37:42.00c",
|
|
"13:37:42.a23",
|
|
"13:37:42.12e",
|
|
"13:37:42.1e1",
|
|
"13:37:42.e11",
|
|
"13:37:42.1",
|
|
"13:37:42.99",
|
|
"13:37:42.0",
|
|
"13:37:42.00",
|
|
"13:37:42.000",
|
|
"13:37:42.-1",
|
|
"13:37:42.1.1",
|
|
"13:37:42.1,1",
|
|
"13:37:42.",
|
|
"foo12:12",
|
|
"13:37:42.100000000000",
|
|
// For color
|
|
"#00ff00",
|
|
"#000000",
|
|
"red",
|
|
"#0f0",
|
|
"#FFFFAA",
|
|
"FFAABB",
|
|
"fFAaBb",
|
|
"FFAAZZ",
|
|
"ABCDEF",
|
|
"#7654321",
|
|
];
|
|
|
|
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");
|
|
|
|
if (type in valueModeValue) {
|
|
element.setAttribute('value', 'tulip');
|
|
element.value = value;
|
|
delayed_is(element.value, sanitizeValue(type, value),
|
|
"The value has not been correctly sanitized for type=" + type);
|
|
delayed_is(element.getAttribute('value'), 'tulip',
|
|
"The content value should not have been sanitized");
|
|
}
|
|
|
|
element.setAttribute('value', '');
|
|
form.reset();
|
|
element.type = 'checkbox'; // We know this type has no sanitizing algorithm.
|
|
element.setAttribute('value', value);
|
|
delayed_is(element.value, value, "The value should not have been sanitized");
|
|
element.type = type;
|
|
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");
|
|
|
|
element.setAttribute('value', '');
|
|
form.reset();
|
|
element.setAttribute('value', value);
|
|
form.reset();
|
|
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");
|
|
|
|
// Cleaning-up.
|
|
element.setAttribute('value', '');
|
|
form.reset();
|
|
}
|
|
|
|
flushDelayedTests(inputTypeDescription);
|
|
}
|
|
|
|
for (type of inputTypes) {
|
|
var form = document.forms[0];
|
|
var element = document.createElement("input");
|
|
element.style.display = "none";
|
|
element.type = type;
|
|
form.appendChild(element);
|
|
|
|
checkSanitizing(element, "type=" + type + ", no frame, no editor");
|
|
|
|
element.style.display = "";
|
|
checkSanitizing(element, "type=" + type + ", frame, no editor");
|
|
|
|
element.focus();
|
|
element.blur();
|
|
checkSanitizing(element, "type=" + type + ", frame, editor");
|
|
|
|
element.style.display = "none";
|
|
checkSanitizing(element, "type=" + type + ", no frame, editor");
|
|
|
|
form.removeChild(element);
|
|
}
|
|
|
|
for (type of todoTypes) {
|
|
// The only meaning of this is to have a failure when new types are introduced
|
|
// so we will know we have to write the tests here.
|
|
var form = document.forms[0];
|
|
var element = document.createElement("input");
|
|
element.type = type;
|
|
form.appendChild(element);
|
|
|
|
todo_is(element.type, type, "");
|
|
|
|
form.removeChild(element);
|
|
}
|
|
|
|
</script>
|
|
</pre>
|
|
</body>
|
|
</html>
|